@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <expected>
|
||||
#include <string>
|
||||
|
||||
#include <modulus.hpp>
|
||||
|
||||
#include <types.hpp>
|
||||
|
||||
namespace vamp_zero {
|
||||
|
||||
struct command_line {
|
||||
std::string config_path{"/etc/product-vamp/vamp.json"};
|
||||
std::bool_t check_config{};
|
||||
std::bool_t health_check{};
|
||||
std::bool_t print_version{};
|
||||
std::bool_t exit_after_startup{};
|
||||
std::bool_t migrate{};
|
||||
};
|
||||
|
||||
auto parse_command_line(std::int32_t argc, std::char_t** argv) -> std::expected<vamp_zero::command_line, modulus::error>;
|
||||
auto run(vamp_zero::command_line command) -> std::expected<void, modulus::error>;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <luma.hpp>
|
||||
|
||||
#include <vamp_style.hpp>
|
||||
|
||||
namespace vamp_zero {
|
||||
|
||||
auto to_luma(vamp_style::color value) -> luma::color;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <expected>
|
||||
#include <string>
|
||||
|
||||
#include <boost/json/value.hpp>
|
||||
|
||||
#include <ligo.hpp>
|
||||
#include <luma.hpp>
|
||||
#include <modulus.hpp>
|
||||
|
||||
#include <types.hpp>
|
||||
#include <vamp_zero/types.hpp>
|
||||
|
||||
namespace vamp_zero {
|
||||
|
||||
struct runtime_config {
|
||||
vamp_zero::hardware_mode hardware{vamp_zero::hardware_mode::REAL};
|
||||
std::bool_t headless{false};
|
||||
std::bool_t exit_after_startup{false};
|
||||
std::string assets_path{"/usr/share/product-vamp"};
|
||||
std::string heartbeat_path{"/run/product-vamp/heartbeat.json"};
|
||||
};
|
||||
|
||||
struct database_config {
|
||||
std::string path{"/var/lib/product-vamp/vamp.db"};
|
||||
std::string migrations_path{"/usr/share/product-vamp/migrations"};
|
||||
};
|
||||
|
||||
struct control_config {
|
||||
ligo::endpoint_config endpoint{
|
||||
.name = "product-vamp-control",
|
||||
.protocol = ligo::protocol::HTTP,
|
||||
.bind = "0.0.0.0:8080",
|
||||
.timeout = std::chrono::milliseconds{5000},
|
||||
.http = {
|
||||
.max_body_size = 64U * 1024U,
|
||||
},
|
||||
};
|
||||
std::string ap_ssid{"Vamp Control"};
|
||||
std::string ap_passphrase{"vamp-control"};
|
||||
std::string ap_interface{"wlan0"};
|
||||
std::string zero_ip{"192.168.42.1"};
|
||||
std::string zero_cidr{"192.168.42.1/24"};
|
||||
};
|
||||
|
||||
struct config {
|
||||
modulus::config modulus{};
|
||||
vamp_zero::runtime_config runtime{};
|
||||
vamp_zero::database_config database{};
|
||||
vamp_zero::control_config control{};
|
||||
luma::application_config display{.title = "Product Vamp"};
|
||||
};
|
||||
|
||||
auto parse_config(boost::json::value const& value) -> std::expected<vamp_zero::config, modulus::error>;
|
||||
auto load_config(std::string const& path) -> std::expected<vamp_zero::config, modulus::error>;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <expected>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/asio/any_io_executor.hpp>
|
||||
#include <boost/asio/awaitable.hpp>
|
||||
|
||||
#include <modulus.hpp>
|
||||
|
||||
#include <vamp_zero/config.hpp>
|
||||
#include <vamp_zero/types.hpp>
|
||||
|
||||
namespace vamp_zero {
|
||||
|
||||
auto async_migrate_database(boost::asio::any_io_executor executor, vamp_zero::database_config config) -> boost::asio::awaitable<std::expected<void, modulus::error>>;
|
||||
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 split_migration_statements(std::string const& input) -> std::expected<std::vector<std::string>, modulus::error>;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <expected>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include <modulus.hpp>
|
||||
|
||||
namespace vamp_zero {
|
||||
|
||||
enum class error_code : std::int32_t {
|
||||
OK = 0,
|
||||
INVALID_ARGUMENT = 1,
|
||||
NOT_FOUND = 2,
|
||||
UNAVAILABLE = 3,
|
||||
PERSISTENCE = 4,
|
||||
CONFLICT = 5,
|
||||
INTERNAL = 6,
|
||||
};
|
||||
|
||||
auto make_error(vamp_zero::error_code code, std::string message, modulus::source_location location = modulus::source_location(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION())) -> modulus::error;
|
||||
auto fail_void(vamp_zero::error_code code, std::string message, modulus::source_location location = modulus::source_location(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION())) -> std::expected<void, modulus::error>;
|
||||
|
||||
template <typename VALUE>
|
||||
auto fail(vamp_zero::error_code code, std::string message, modulus::source_location location = modulus::source_location(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION())) -> std::expected<VALUE, modulus::error>;
|
||||
|
||||
}
|
||||
|
||||
template <typename VALUE>
|
||||
auto vamp_zero::fail(vamp_zero::error_code code, std::string message, modulus::source_location location) -> std::expected<VALUE, modulus::error> {
|
||||
return modulus::fail<VALUE>(vamp_zero::make_error(code, std::move(message), location));
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <expected>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include <modulus.hpp>
|
||||
|
||||
#include <vamp_zero/types.hpp>
|
||||
|
||||
namespace vamp_zero {
|
||||
|
||||
auto parse_score_document(std::string_view json, std::string source_path = {}) -> std::expected<vamp_zero::score_document, 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;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <expected>
|
||||
#include <string>
|
||||
|
||||
#include <boost/json/value.hpp>
|
||||
|
||||
#include <modulus.hpp>
|
||||
|
||||
#include <vamp_protocol/page_control.hpp>
|
||||
#include <vamp_zero/types.hpp>
|
||||
|
||||
namespace vamp_zero {
|
||||
|
||||
auto apply_app_command(vamp_zero::app_state state, vamp_protocol::page_command command) -> vamp_zero::app_state;
|
||||
auto app_status_json(vamp_zero::app_state const& state) -> boost::json::value;
|
||||
auto remote_display_text(vamp_zero::app_state const& state) -> std::string;
|
||||
auto validate_app_state(vamp_zero::app_state const& state) -> std::expected<void, modulus::error>;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
|
||||
#include <boost/json/value.hpp>
|
||||
|
||||
#include <ligo.hpp>
|
||||
|
||||
#include <vamp_protocol/page_control.hpp>
|
||||
#include <vamp_zero/config.hpp>
|
||||
#include <vamp_zero/types.hpp>
|
||||
|
||||
namespace vamp_zero {
|
||||
|
||||
class control_state {
|
||||
public:
|
||||
using observer = std::function<void(vamp_zero::app_state)>;
|
||||
|
||||
control_state(vamp_zero::config config, vamp_zero::app_state state);
|
||||
auto config() const -> vamp_zero::config;
|
||||
auto snapshot() const -> vamp_zero::app_state;
|
||||
auto apply(vamp_protocol::page_command command) -> vamp_zero::app_state;
|
||||
auto heartbeat() -> vamp_zero::app_state;
|
||||
auto refresh_connection() -> std::optional<vamp_zero::app_state>;
|
||||
auto set_observer(vamp_zero::control_state::observer observer) -> void;
|
||||
private:
|
||||
auto pico_connected_locked() const -> std::bool_t;
|
||||
auto snapshot_locked() const -> vamp_zero::app_state;
|
||||
mutable std::mutex mutex_{};
|
||||
vamp_zero::config config_{};
|
||||
vamp_zero::app_state state_{};
|
||||
std::chrono::steady_clock::time_point last_heartbeat_{};
|
||||
vamp_zero::control_state::observer observer_{};
|
||||
};
|
||||
|
||||
auto make_router(vamp_zero::control_state& state) -> ligo::service_router;
|
||||
auto portal_status_json(vamp_zero::config const& config, vamp_zero::app_state const& state) -> boost::json::value;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <luma.hpp>
|
||||
|
||||
#include <vamp_zero/types.hpp>
|
||||
|
||||
namespace vamp_zero {
|
||||
|
||||
constexpr auto score_measures_per_system = std::size_t{4};
|
||||
constexpr auto score_systems_per_page = std::size_t{3};
|
||||
constexpr auto score_measures_per_page = score_measures_per_system * score_systems_per_page;
|
||||
|
||||
auto draw_score_page(luma::draw_context& context, luma::rect bounds, vamp_zero::score_document const& score, std::size_t page_index) -> void;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include <types.hpp>
|
||||
|
||||
namespace vamp_zero {
|
||||
|
||||
enum class hardware_mode {
|
||||
FAKE,
|
||||
REAL,
|
||||
};
|
||||
|
||||
struct score_pitch {
|
||||
std::char_t letter{'c'};
|
||||
std::int32_t octave{};
|
||||
std::string accidental{};
|
||||
};
|
||||
|
||||
struct score_note {
|
||||
std::string id{};
|
||||
std::string kind{};
|
||||
std::bool_t hidden{};
|
||||
std::int64_t duration_ticks{};
|
||||
std::int64_t display_ticks{};
|
||||
std::string notehead{};
|
||||
std::string chord_symbol{};
|
||||
std::string lyric{};
|
||||
std::bool_t tie_to_next{};
|
||||
std::bool_t tie_from_previous{};
|
||||
std::vector<vamp_zero::score_pitch> pitches{};
|
||||
};
|
||||
|
||||
struct score_measure {
|
||||
std::string id{};
|
||||
std::string section_label{};
|
||||
std::string time_signature{};
|
||||
std::string key_signature{};
|
||||
std::vector<vamp_zero::score_note> notes{};
|
||||
};
|
||||
|
||||
struct score_document {
|
||||
std::string id{};
|
||||
std::string title{};
|
||||
std::string composer{};
|
||||
std::string key_signature{};
|
||||
std::string part{};
|
||||
std::string arrangement_part_type{};
|
||||
std::string source_path{};
|
||||
std::string source_json{};
|
||||
std::vector<vamp_zero::score_measure> measures{};
|
||||
};
|
||||
|
||||
struct library_part {
|
||||
std::string id{};
|
||||
std::string title{};
|
||||
std::string composer{};
|
||||
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{};
|
||||
};
|
||||
|
||||
struct song_group {
|
||||
std::string title{};
|
||||
std::string composer{};
|
||||
std::vector<vamp_zero::library_part> parts{};
|
||||
};
|
||||
|
||||
struct library_state {
|
||||
std::vector<vamp_zero::library_part> parts{};
|
||||
std::vector<vamp_zero::song_group> groups{};
|
||||
};
|
||||
|
||||
struct practice_exercise {
|
||||
struct score_variant {
|
||||
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{};
|
||||
};
|
||||
|
||||
std::string id{};
|
||||
std::string practice_type_id{};
|
||||
std::string practice_type_title{};
|
||||
std::string lesson_group_id{};
|
||||
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::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{};
|
||||
};
|
||||
|
||||
struct practice_type_group {
|
||||
std::string id{};
|
||||
std::string title{};
|
||||
std::vector<vamp_zero::practice_lesson_group> lesson_groups{};
|
||||
};
|
||||
|
||||
struct practice_library {
|
||||
std::vector<vamp_zero::practice_exercise> exercises{};
|
||||
std::vector<vamp_zero::practice_type_group> types{};
|
||||
};
|
||||
|
||||
enum class app_mode {
|
||||
MAIN_MENU,
|
||||
PERFORMANCE_SONG_MENU,
|
||||
PERFORMANCE_PART_MENU,
|
||||
PERFORMANCE_SCORE,
|
||||
PRACTICE_TYPE_MENU,
|
||||
PRACTICE_LESSON_MENU,
|
||||
PRACTICE_EXERCISE_MENU,
|
||||
PRACTICE_KEY_MENU,
|
||||
PRACTICE_SCORE,
|
||||
};
|
||||
|
||||
struct app_state {
|
||||
vamp_zero::library_state performance{};
|
||||
vamp_zero::practice_library practice{};
|
||||
vamp_zero::app_mode mode{vamp_zero::app_mode::MAIN_MENU};
|
||||
std::size_t selected_main_menu_index{};
|
||||
std::size_t selected_song_index{};
|
||||
std::size_t selected_part_index{};
|
||||
std::size_t selected_practice_type_index{};
|
||||
std::size_t selected_practice_lesson_index{};
|
||||
std::size_t selected_practice_exercise_index{};
|
||||
std::size_t selected_practice_key_index{};
|
||||
std::string active_part_id{};
|
||||
std::string active_practice_id{};
|
||||
std::size_t page_index{};
|
||||
std::uint64_t next_count{};
|
||||
std::uint64_t previous_count{};
|
||||
std::uint64_t select_count{};
|
||||
std::uint64_t heartbeat_count{};
|
||||
std::string last_command{"startup"};
|
||||
std::bool_t pico_connected{false};
|
||||
};
|
||||
|
||||
auto to_string(vamp_zero::hardware_mode value) -> std::string;
|
||||
auto to_string(vamp_zero::app_mode value) -> std::string;
|
||||
auto practice_key_names() -> std::vector<std::string_view> const&;
|
||||
auto practice_type_supports_key_selection(std::string_view practice_type_id) -> std::bool_t;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include <expected>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
#include <boost/asio/any_io_executor.hpp>
|
||||
|
||||
#include <luma.hpp>
|
||||
#include <modulus.hpp>
|
||||
|
||||
#include <vamp_zero/config.hpp>
|
||||
#include <vamp_zero/types.hpp>
|
||||
|
||||
namespace vamp_zero {
|
||||
|
||||
struct ui_state {
|
||||
vamp_zero::app_state app{};
|
||||
std::string ap_ssid{};
|
||||
std::string zero_ip{};
|
||||
std::uint16_t port{8080};
|
||||
};
|
||||
|
||||
class zero_ui {
|
||||
public:
|
||||
zero_ui(boost::asio::any_io_executor executor, luma::application_config config);
|
||||
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 make_root(vamp_zero::ui_state const& state) -> std::expected<std::unique_ptr<luma::control>, modulus::error>;
|
||||
boost::asio::any_io_executor executor_;
|
||||
luma::application application_;
|
||||
mutable std::mutex mutex_{};
|
||||
vamp_zero::ui_state state_{};
|
||||
};
|
||||
|
||||
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