+184
@@ -22,12 +22,17 @@
|
||||
#include <boost/asio/co_spawn.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/use_future.hpp>
|
||||
#include <boost/json/object.hpp>
|
||||
#include <boost/json/parse.hpp>
|
||||
|
||||
#include <noto.hpp>
|
||||
|
||||
#include <vamp_protocol/page_control.hpp>
|
||||
#include <vamp_zero/config.hpp>
|
||||
#include <vamp_pico/http_client.hpp>
|
||||
#include <vamp_zero/database.hpp>
|
||||
#include <vamp_zero/library.hpp>
|
||||
#include <vamp_zero/page_control.hpp>
|
||||
#include <vamp_zero/score.hpp>
|
||||
#include <vamp_zero/types.hpp>
|
||||
|
||||
@@ -311,6 +316,65 @@ auto score_asset_json(std::string title, std::string key = "C") -> std::string {
|
||||
)json";
|
||||
}
|
||||
|
||||
auto navigation_state() -> vamp_zero::app_state {
|
||||
auto part = vamp_zero::library_part{
|
||||
.id = "part-lead",
|
||||
.title = "Navigation Tune",
|
||||
.composer = "Composer",
|
||||
.key_signature = "C",
|
||||
.part = "Lead",
|
||||
.source_path = "navigation.json",
|
||||
.source_json = score_asset_json("Navigation Tune"),
|
||||
.measure_count = 1,
|
||||
.total_pages = 2,
|
||||
};
|
||||
auto variant = vamp_zero::practice_exercise::score_variant{
|
||||
.id = "exercise-c",
|
||||
.key_signature = "C",
|
||||
.source_path = "exercise.json",
|
||||
.source_json = score_asset_json("Exercise"),
|
||||
.measure_count = 1,
|
||||
.total_pages = 1,
|
||||
};
|
||||
auto exercise = vamp_zero::practice_exercise{
|
||||
.id = "exercise-1",
|
||||
.practice_type_id = "scale",
|
||||
.practice_type_title = "Scales",
|
||||
.lesson_group_id = "lesson-1",
|
||||
.lesson_group_title = "Major",
|
||||
.title = "C Major",
|
||||
.composer = "Composer",
|
||||
.key_signature = "C",
|
||||
.source_path = "exercise.json",
|
||||
.source_json = score_asset_json("Exercise"),
|
||||
.measure_count = 1,
|
||||
.total_pages = 1,
|
||||
.variants = {variant},
|
||||
};
|
||||
return vamp_zero::app_state{
|
||||
.performance = {
|
||||
.parts = {part},
|
||||
.groups = {{
|
||||
.title = part.title,
|
||||
.composer = part.composer,
|
||||
.parts = {part},
|
||||
}},
|
||||
},
|
||||
.practice = {
|
||||
.exercises = {exercise},
|
||||
.types = {{
|
||||
.id = "scale",
|
||||
.title = "Scales",
|
||||
.lesson_groups = {{
|
||||
.id = "lesson-1",
|
||||
.title = "Major",
|
||||
.exercises = {exercise},
|
||||
}},
|
||||
}},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
void write_text(std::filesystem::path const& path, std::string const& text) {
|
||||
std::filesystem::create_directories(path.parent_path());
|
||||
auto output = std::ofstream{path, std::ios::binary | std::ios::trunc};
|
||||
@@ -319,6 +383,126 @@ void write_text(std::filesystem::path const& path, std::string const& text) {
|
||||
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(product_vamp_audio_config_parses_defaults_and_values) {
|
||||
auto defaults = vamp_zero::parse_config(boost::json::parse(R"json({})json"));
|
||||
BOOST_REQUIRE(defaults);
|
||||
BOOST_TEST(defaults->audio.enabled);
|
||||
BOOST_TEST(!defaults->audio.track_enabled);
|
||||
BOOST_TEST(!defaults->audio.metronome_enabled);
|
||||
BOOST_TEST(defaults->audio.metronome_bpm == 120U);
|
||||
BOOST_TEST(defaults->audio.metronome_min_bpm == 40U);
|
||||
BOOST_TEST(defaults->audio.metronome_max_bpm == 240U);
|
||||
BOOST_TEST(defaults->audio.metronome_step == 5U);
|
||||
|
||||
auto parsed = vamp_zero::parse_config(boost::json::parse(R"json({
|
||||
"audio": {
|
||||
"enabled": false,
|
||||
"track_enabled": true,
|
||||
"metronome_enabled": true,
|
||||
"metronome_bpm": 90,
|
||||
"metronome_min_bpm": 50,
|
||||
"metronome_max_bpm": 180,
|
||||
"metronome_step": 10,
|
||||
"beats_per_bar": 3,
|
||||
"master_volume": 0.5,
|
||||
"metronome_volume": 0.25
|
||||
}
|
||||
})json"));
|
||||
BOOST_REQUIRE(parsed);
|
||||
BOOST_TEST(!parsed->audio.enabled);
|
||||
BOOST_TEST(parsed->audio.track_enabled);
|
||||
BOOST_TEST(parsed->audio.metronome_enabled);
|
||||
BOOST_TEST(parsed->audio.metronome_bpm == 90U);
|
||||
BOOST_TEST(parsed->audio.metronome_min_bpm == 50U);
|
||||
BOOST_TEST(parsed->audio.metronome_max_bpm == 180U);
|
||||
BOOST_TEST(parsed->audio.metronome_step == 10U);
|
||||
BOOST_TEST(parsed->audio.beats_per_bar == 3U);
|
||||
BOOST_TEST(parsed->audio.master_volume == 0.5F);
|
||||
BOOST_TEST(parsed->audio.metronome_volume == 0.25F);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(product_vamp_audio_config_rejects_invalid_tempo_range) {
|
||||
auto parsed = vamp_zero::parse_config(boost::json::parse(R"json({
|
||||
"audio": {
|
||||
"metronome_bpm": 120,
|
||||
"metronome_min_bpm": 160,
|
||||
"metronome_max_bpm": 80
|
||||
}
|
||||
})json"));
|
||||
BOOST_TEST(!parsed);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(main_menu_toggles_audio_settings_and_edits_tempo) {
|
||||
auto state = navigation_state();
|
||||
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::NEXT);
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::NEXT);
|
||||
BOOST_TEST(state.selected_main_menu_index == 2U);
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::SELECT);
|
||||
BOOST_TEST(state.audio.track_enabled);
|
||||
BOOST_TEST(static_cast<int>(state.mode) == static_cast<int>(vamp_zero::app_mode::MAIN_MENU));
|
||||
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::NEXT);
|
||||
BOOST_TEST(state.selected_main_menu_index == 3U);
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::SELECT);
|
||||
BOOST_TEST(state.audio.metronome_enabled);
|
||||
BOOST_TEST(static_cast<int>(state.mode) == static_cast<int>(vamp_zero::app_mode::MAIN_MENU));
|
||||
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::NEXT);
|
||||
BOOST_TEST(state.selected_main_menu_index == 4U);
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::SELECT);
|
||||
BOOST_TEST(state.audio.tempo_editing);
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::NEXT);
|
||||
BOOST_TEST(state.audio.metronome_bpm == 125U);
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::PREVIOUS);
|
||||
BOOST_TEST(state.audio.metronome_bpm == 120U);
|
||||
for (auto index = 0; index < 40; ++index) {
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::PREVIOUS);
|
||||
}
|
||||
BOOST_TEST(state.audio.metronome_bpm == 40U);
|
||||
for (auto index = 0; index < 80; ++index) {
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::NEXT);
|
||||
}
|
||||
BOOST_TEST(state.audio.metronome_bpm == 240U);
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::SELECT);
|
||||
BOOST_TEST(!state.audio.tempo_editing);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(audio_status_json_reports_menu_settings) {
|
||||
auto state = navigation_state();
|
||||
state.audio.track_enabled = true;
|
||||
state.audio.metronome_enabled = true;
|
||||
state.audio.metronome_bpm = 135;
|
||||
state.audio.tempo_editing = true;
|
||||
|
||||
auto status = vamp_zero::app_status_json(state).as_object();
|
||||
auto const& audio = status.at("audio").as_object();
|
||||
BOOST_TEST(audio.at("track_enabled").as_bool());
|
||||
BOOST_TEST(audio.at("metronome_enabled").as_bool());
|
||||
BOOST_TEST(audio.at("metronome_bpm").as_uint64() == 135U);
|
||||
BOOST_TEST(audio.at("metronome_min_bpm").as_uint64() == 40U);
|
||||
BOOST_TEST(audio.at("metronome_max_bpm").as_uint64() == 240U);
|
||||
BOOST_TEST(audio.at("metronome_step").as_uint64() == 5U);
|
||||
BOOST_TEST(audio.at("tempo_editing").as_bool());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(main_menu_metronome_setting_survives_score_selection) {
|
||||
auto state = navigation_state();
|
||||
state.audio.metronome_enabled = true;
|
||||
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::SELECT);
|
||||
BOOST_TEST(static_cast<int>(state.mode) == static_cast<int>(vamp_zero::app_mode::PERFORMANCE_SONG_MENU));
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::NEXT);
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::SELECT);
|
||||
BOOST_TEST(static_cast<int>(state.mode) == static_cast<int>(vamp_zero::app_mode::PERFORMANCE_PART_MENU));
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::NEXT);
|
||||
state = vamp_zero::apply_app_command(std::move(state), vamp_protocol::page_command::SELECT);
|
||||
|
||||
BOOST_TEST(static_cast<int>(state.mode) == static_cast<int>(vamp_zero::app_mode::PERFORMANCE_SCORE));
|
||||
BOOST_TEST(state.audio.metronome_enabled);
|
||||
BOOST_TEST(!state.audio.tempo_editing);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(score_parser_preserves_notation_preamble) {
|
||||
auto parsed = vamp_zero::parse_score_document(R"json(
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user