Initial public khodo snapshot
ci / checks (push) Successful in 38m58s

This commit is contained in:
khodowany
2026-09-04 19:30:11 -05:00
commit 4f9a269f85
99 changed files with 59585 additions and 0 deletions
+25
View File
@@ -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>;
}
+11
View File
@@ -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;
}
+59
View File
@@ -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>;
}
+23
View File
@@ -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>;
}
+33
View File
@@ -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));
}
+20
View File
@@ -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;
}
+20
View File
@@ -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>;
}
+42
View File
@@ -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;
}
+17
View File
@@ -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;
}
+162
View File
@@ -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;
}
+43
View File
@@ -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;
}