Shared Catalog
This commit is contained in:
@@ -23,11 +23,12 @@ public:
|
||||
auto fill_rect(std::int32_t x, std::int32_t y, std::int32_t width, std::int32_t height, std::uint16_t color) -> void;
|
||||
auto draw_text(std::int32_t x, std::int32_t y, std::char_t const *text, std::uint16_t color, std::int32_t scale = 2) -> void;
|
||||
auto show_boot(std::char_t const *line1, std::char_t const *line2, std::uint16_t accent) -> void;
|
||||
auto show_remote(vamp_style::color status, std::char_t const *title, std::char_t const *part, std::uint32_t page, std::uint32_t pages, std::bool_t active) -> void;
|
||||
auto show_remote(vamp_style::color status, std::char_t const *title, std::char_t const *part, std::uint32_t page, std::uint32_t pages, std::bool_t active, std::bool_t busy = false) -> void;
|
||||
private:
|
||||
std::bool_t remote_valid_{};
|
||||
vamp_style::color last_status_{};
|
||||
std::bool_t last_active_{};
|
||||
std::bool_t last_busy_{};
|
||||
std::array<std::char_t, 96> last_title_{};
|
||||
std::array<std::char_t, 48> last_part_{};
|
||||
std::uint32_t last_page_{};
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
||||
#include <vamp_protocol/page_control.hpp>
|
||||
#include <vamp_pico/input.hpp>
|
||||
#include <modulus/types.hpp>
|
||||
|
||||
|
||||
struct tcp_pcb;
|
||||
|
||||
namespace vamp_pico {
|
||||
|
||||
struct remote_display_state {
|
||||
@@ -19,8 +24,50 @@ struct remote_display_state {
|
||||
};
|
||||
|
||||
auto parse_remote_display_body(std::string_view body, vamp_pico::remote_display_state &state) -> std::bool_t;
|
||||
auto post_remote_command(vamp_protocol::page_command command, vamp_pico::remote_display_state &state) -> std::bool_t;
|
||||
auto heartbeat() -> std::bool_t;
|
||||
auto fetch_remote_display(vamp_pico::remote_display_state &state) -> std::bool_t;
|
||||
|
||||
enum class http_status {
|
||||
IDLE,
|
||||
IN_FLIGHT,
|
||||
READY,
|
||||
};
|
||||
|
||||
enum class http_start_result {
|
||||
STARTED,
|
||||
BUSY,
|
||||
};
|
||||
|
||||
struct http_result {
|
||||
remote_request request{};
|
||||
std::bool_t success{};
|
||||
remote_display_state display{};
|
||||
};
|
||||
|
||||
class http_client {
|
||||
public:
|
||||
http_client() = default;
|
||||
~http_client();
|
||||
http_client(http_client const &) = delete;
|
||||
auto operator=(http_client const &) -> http_client & = delete;
|
||||
http_client(http_client &&) = delete;
|
||||
auto operator=(http_client &&) -> http_client & = delete;
|
||||
// Accepted requests, including immediate failures, produce exactly one result.
|
||||
auto start(remote_request request, std::uint64_t now_ms) -> http_start_result;
|
||||
auto poll(std::uint64_t now_ms) -> http_status;
|
||||
auto take_result() -> std::optional<http_result>;
|
||||
// Discards the request/result and returns to IDLE. Call before Wi-Fi deinit.
|
||||
auto cancel() -> void;
|
||||
private:
|
||||
friend struct http_client_callbacks;
|
||||
tcp_pcb *pcb_{};
|
||||
http_status status_{http_status::IDLE};
|
||||
remote_request request_{};
|
||||
std::bool_t success_{};
|
||||
std::uint64_t started_ms_{};
|
||||
std::uint64_t timeout_ms_{};
|
||||
std::array<std::char_t, 384> request_buffer_{};
|
||||
std::size_t request_size_{};
|
||||
std::array<std::char_t, 1024> response_buffer_{};
|
||||
std::size_t response_size_{};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
||||
#include <vamp_protocol/page_control.hpp>
|
||||
|
||||
|
||||
namespace vamp_pico {
|
||||
|
||||
enum class request_kind {
|
||||
DISPLAY,
|
||||
COMMAND,
|
||||
HEARTBEAT,
|
||||
};
|
||||
|
||||
struct remote_request {
|
||||
request_kind kind{request_kind::DISPLAY};
|
||||
vamp_protocol::page_command command{vamp_protocol::page_command::NEXT};
|
||||
};
|
||||
|
||||
class gesture_state {
|
||||
public:
|
||||
auto update(std::bool_t touching, std::uint64_t now_ms) -> std::optional<vamp_protocol::page_command>;
|
||||
private:
|
||||
std::bool_t touching_{};
|
||||
std::bool_t hold_sent_{};
|
||||
std::bool_t pending_tap_{};
|
||||
std::uint64_t down_ms_{};
|
||||
std::uint64_t last_up_ms_{};
|
||||
};
|
||||
|
||||
enum class enqueue_result {
|
||||
QUEUED,
|
||||
BUSY,
|
||||
};
|
||||
|
||||
class request_scheduler {
|
||||
public:
|
||||
static constexpr auto command_capacity = std::size_t{16};
|
||||
auto enqueue(vamp_protocol::page_command command) -> enqueue_result;
|
||||
auto next(std::uint64_t now_ms) -> std::optional<remote_request>;
|
||||
auto complete(std::uint64_t now_ms) -> void;
|
||||
auto queued() const -> std::size_t;
|
||||
private:
|
||||
std::array<vamp_protocol::page_command, command_capacity> commands_{};
|
||||
std::size_t head_{};
|
||||
std::size_t size_{};
|
||||
std::bool_t in_flight_{};
|
||||
std::bool_t completed_{};
|
||||
std::uint64_t completed_ms_{};
|
||||
};
|
||||
|
||||
}
|
||||
@@ -18,5 +18,6 @@ auto async_ensure_database(boost::asio::any_io_executor executor, vamp_zero::dat
|
||||
auto async_import_catalogs(boost::asio::any_io_executor executor, vamp_zero::database_config config, std::string assets_path) -> boost::asio::awaitable<std::expected<void, modulus::error>>;
|
||||
auto async_load_performance_library(boost::asio::any_io_executor executor, vamp_zero::database_config config) -> boost::asio::awaitable<std::expected<vamp_zero::library_state, modulus::error>>;
|
||||
auto async_load_practice_library(boost::asio::any_io_executor executor, vamp_zero::database_config config) -> boost::asio::awaitable<std::expected<vamp_zero::practice_library, modulus::error>>;
|
||||
auto async_load_score(boost::asio::any_io_executor executor, vamp_zero::database_config config, vamp_zero::score_reference reference) -> boost::asio::awaitable<std::expected<vamp_zero::score_document, modulus::error>>;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <expected>
|
||||
|
||||
#include <vamp_zero/config.hpp>
|
||||
|
||||
|
||||
namespace vamp_zero {
|
||||
|
||||
auto check_health(vamp_zero::config const &config) -> std::expected<void, modulus::error>;
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <expected>
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
@@ -12,9 +13,13 @@
|
||||
namespace vamp_zero {
|
||||
|
||||
auto parse_score_document(std::string_view json, std::string source_path = {}) -> std::expected<vamp_zero::score_document, modulus::error>;
|
||||
auto read_score_document(std::filesystem::path const &path) -> std::expected<vamp_zero::score_document, modulus::error>;
|
||||
auto score_paths(std::string const &assets_path, vamp_zero::score_category category) -> std::expected<std::vector<std::filesystem::path>, modulus::error>;
|
||||
auto performance_metadata(vamp_zero::score_document const &document) -> vamp_zero::library_part;
|
||||
auto practice_metadata(vamp_zero::score_document const &document, std::string const &assets_path) -> std::expected<vamp_zero::practice_exercise, modulus::error>;
|
||||
auto load_performance_library(std::string const &assets_path) -> std::expected<vamp_zero::library_state, modulus::error>;
|
||||
auto load_practice_library(std::string const &assets_path) -> std::expected<vamp_zero::practice_library, modulus::error>;
|
||||
auto group_library_parts(std::vector<vamp_zero::library_part> parts) -> vamp_zero::library_state;
|
||||
auto group_practice_exercises(std::vector<vamp_zero::practice_exercise> exercises) -> vamp_zero::practice_library;
|
||||
auto group_practice_exercises(std::vector<vamp_zero::practice_exercise> exercises) -> std::expected<vamp_zero::practice_library, modulus::error>;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include <expected>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include <boost/asio/any_io_executor.hpp>
|
||||
#include <boost/asio/awaitable.hpp>
|
||||
|
||||
#include <modulus.hpp>
|
||||
#include <vamp_zero/types.hpp>
|
||||
|
||||
namespace vamp_zero {
|
||||
|
||||
struct score_load_state {
|
||||
std::shared_ptr<vamp_zero::score_document const> document{};
|
||||
std::optional<modulus::error> error{};
|
||||
std::bool_t loading{};
|
||||
};
|
||||
|
||||
class score_loader {
|
||||
public:
|
||||
// An already-running completion may overlap stop; capture its consumer weakly.
|
||||
score_loader(boost::asio::any_io_executor executor,
|
||||
std::function<boost::asio::awaitable<std::expected<vamp_zero::score_document, modulus::error>>(vamp_zero::score_reference)> load,
|
||||
std::function<void()> completed = {});
|
||||
~score_loader();
|
||||
score_loader(score_loader const &) = delete;
|
||||
auto operator=(score_loader const &) -> score_loader & = delete;
|
||||
auto select(std::shared_ptr<vamp_zero::catalogue const> catalog, std::optional<vamp_zero::score_reference> reference) -> void;
|
||||
auto snapshot() const -> vamp_zero::score_load_state;
|
||||
auto stop() -> void;
|
||||
private:
|
||||
struct state;
|
||||
std::shared_ptr<state> state_;
|
||||
};
|
||||
|
||||
auto selected_score_reference(vamp_zero::app_state const &state) -> std::optional<vamp_zero::score_reference>;
|
||||
|
||||
}
|
||||
+24
-11
@@ -3,6 +3,7 @@
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
@@ -28,6 +29,7 @@ struct score_document {
|
||||
std::string title{};
|
||||
std::string composer{};
|
||||
std::string key_signature{};
|
||||
std::string authored_key_signature{};
|
||||
std::string time_signature{};
|
||||
std::string part{};
|
||||
std::string arrangement_part_type{};
|
||||
@@ -44,7 +46,6 @@ struct library_part {
|
||||
std::string key_signature{};
|
||||
std::string part{};
|
||||
std::string source_path{};
|
||||
std::string source_json{};
|
||||
std::size_t measure_count{};
|
||||
std::size_t total_pages{};
|
||||
};
|
||||
@@ -52,7 +53,7 @@ struct library_part {
|
||||
struct song_group {
|
||||
std::string title{};
|
||||
std::string composer{};
|
||||
std::vector<vamp_zero::library_part> parts{};
|
||||
std::vector<std::size_t> parts{};
|
||||
};
|
||||
|
||||
struct library_state {
|
||||
@@ -65,7 +66,6 @@ struct practice_exercise {
|
||||
std::string id{};
|
||||
std::string key_signature{};
|
||||
std::string source_path{};
|
||||
std::string source_json{};
|
||||
std::size_t measure_count{};
|
||||
std::size_t total_pages{};
|
||||
};
|
||||
@@ -76,18 +76,14 @@ struct practice_exercise {
|
||||
std::string lesson_group_title{};
|
||||
std::string title{};
|
||||
std::string composer{};
|
||||
std::string key_signature{};
|
||||
std::string source_path{};
|
||||
std::string source_json{};
|
||||
std::size_t measure_count{};
|
||||
std::size_t total_pages{};
|
||||
std::string authored_key_signature{};
|
||||
std::vector<vamp_zero::practice_exercise::score_variant> variants{};
|
||||
};
|
||||
|
||||
struct practice_lesson_group {
|
||||
std::string id{};
|
||||
std::string title{};
|
||||
std::vector<vamp_zero::practice_exercise> exercises{};
|
||||
std::vector<std::size_t> exercises{};
|
||||
};
|
||||
|
||||
struct practice_type_group {
|
||||
@@ -101,6 +97,24 @@ struct practice_library {
|
||||
std::vector<vamp_zero::practice_type_group> types{};
|
||||
};
|
||||
|
||||
struct catalogue {
|
||||
vamp_zero::library_state performance{};
|
||||
vamp_zero::practice_library practice{};
|
||||
};
|
||||
|
||||
auto empty_catalogue() -> std::shared_ptr<vamp_zero::catalogue const> const &;
|
||||
|
||||
enum class score_category {
|
||||
PERFORMANCE,
|
||||
PRACTICE,
|
||||
};
|
||||
|
||||
struct score_reference {
|
||||
vamp_zero::score_category category{vamp_zero::score_category::PERFORMANCE};
|
||||
std::string id{};
|
||||
auto operator==(vamp_zero::score_reference const &) const -> std::bool_t = default;
|
||||
};
|
||||
|
||||
enum class app_mode {
|
||||
MAIN_MENU,
|
||||
PERFORMANCE_SONG_MENU,
|
||||
@@ -124,8 +138,7 @@ struct audio_state {
|
||||
};
|
||||
|
||||
struct app_state {
|
||||
vamp_zero::library_state performance{};
|
||||
vamp_zero::practice_library practice{};
|
||||
std::shared_ptr<vamp_zero::catalogue const> catalog{vamp_zero::empty_catalogue()};
|
||||
vamp_zero::app_mode mode{vamp_zero::app_mode::MAIN_MENU};
|
||||
vamp_zero::audio_state audio{};
|
||||
std::size_t selected_main_menu_index{};
|
||||
|
||||
+10
-24
@@ -1,16 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <expected>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include <boost/asio/any_io_executor.hpp>
|
||||
#include <boost/asio/steady_timer.hpp>
|
||||
|
||||
#include <luma.hpp>
|
||||
#include <modulus.hpp>
|
||||
@@ -21,7 +17,9 @@
|
||||
|
||||
namespace vamp_zero {
|
||||
|
||||
struct score_draw_cache;
|
||||
struct ui_runtime;
|
||||
|
||||
class score_loader;
|
||||
|
||||
struct ui_state {
|
||||
vamp_zero::app_state app{};
|
||||
@@ -32,30 +30,18 @@ struct ui_state {
|
||||
|
||||
class zero_ui {
|
||||
public:
|
||||
zero_ui(boost::asio::any_io_executor executor, luma::application_config config, std::function<void(vamp_protocol::page_command)> command_handler = {});
|
||||
zero_ui(boost::asio::any_io_executor executor, luma::application_config config, vamp_zero::database_config database, std::function<void(vamp_protocol::page_command)> command_handler = {});
|
||||
~zero_ui();
|
||||
zero_ui(zero_ui const &) = delete;
|
||||
auto operator=(zero_ui const &) -> zero_ui & = delete;
|
||||
auto run() -> std::expected<void, modulus::error>;
|
||||
auto stop() -> void;
|
||||
auto publish(vamp_zero::ui_state state) -> std::expected<void, modulus::error>;
|
||||
auto snapshot() const -> vamp_zero::ui_state;
|
||||
private:
|
||||
auto handle_touch(luma::touch_event const &event) -> std::bool_t;
|
||||
auto send_touch_command(vamp_protocol::page_command command) -> void;
|
||||
auto arm_pending_tap() -> void;
|
||||
auto cancel_pending_tap_locked() -> void;
|
||||
auto make_root(vamp_zero::ui_state const &state) -> std::expected<std::unique_ptr<luma::control>, modulus::error>;
|
||||
boost::asio::any_io_executor executor_;
|
||||
boost::asio::steady_timer tap_timer_;
|
||||
luma::application application_;
|
||||
std::function<void(vamp_protocol::page_command)> command_handler_{};
|
||||
std::shared_ptr<vamp_zero::score_draw_cache> score_cache_{};
|
||||
mutable std::mutex mutex_{};
|
||||
vamp_zero::ui_state state_{};
|
||||
mutable std::mutex touch_mutex_{};
|
||||
std::optional<std::int32_t> active_touch_id_{};
|
||||
std::chrono::steady_clock::time_point touch_down_time_{};
|
||||
std::chrono::steady_clock::time_point last_tap_time_{};
|
||||
std::bool_t hold_sent_{};
|
||||
std::bool_t pending_tap_{};
|
||||
std::shared_ptr<luma::application> application_;
|
||||
std::shared_ptr<vamp_zero::ui_runtime> runtime_;
|
||||
std::shared_ptr<vamp_zero::score_loader> score_loader_;
|
||||
};
|
||||
|
||||
auto make_ui_state(vamp_zero::config const &config, vamp_zero::app_state app) -> vamp_zero::ui_state;
|
||||
|
||||
Reference in New Issue
Block a user