Shared Catalog
This commit is contained in:
@@ -66,16 +66,19 @@ auto decrease_bpm(vamp_zero::audio_state &audio) -> void {
|
||||
}
|
||||
|
||||
auto clamp_state(vamp_zero::app_state state) -> vamp_zero::app_state {
|
||||
if (!state.catalog) {
|
||||
state.catalog = vamp_zero::empty_catalogue();
|
||||
}
|
||||
state.audio = clamp_audio_state(state.audio);
|
||||
state.selected_main_menu_index = std::min(state.selected_main_menu_index, main_menu_count - 1U);
|
||||
state.selected_song_index = std::min(state.selected_song_index, menu_row_count(state.performance.groups.size()) - 1U);
|
||||
state.selected_song_index = std::min(state.selected_song_index, menu_row_count(state.catalog->performance.groups.size()) - 1U);
|
||||
if (auto const *group = selected_group(state); group != nullptr) {
|
||||
state.selected_part_index = std::min(state.selected_part_index, menu_row_count(group->parts.size()) - 1U);
|
||||
} else {
|
||||
state.selected_part_index = 0U;
|
||||
}
|
||||
state.selected_practice_type_index =
|
||||
std::min(state.selected_practice_type_index, menu_row_count(state.practice.types.size()) - 1U);
|
||||
std::min(state.selected_practice_type_index, menu_row_count(state.catalog->practice.types.size()) - 1U);
|
||||
if (auto const *type = selected_practice_type(state); type != nullptr) {
|
||||
state.selected_practice_lesson_index =
|
||||
std::min(state.selected_practice_lesson_index, menu_row_count(type->lesson_groups.size()) - 1U);
|
||||
@@ -192,19 +195,23 @@ auto exercise_json(vamp_zero::practice_exercise const &exercise) -> boost::json:
|
||||
result["supports_key_selection"] = supports_key_selection(exercise);
|
||||
result["title"] = exercise.title;
|
||||
result["composer"] = exercise.composer;
|
||||
result["key_signature"] = exercise.key_signature;
|
||||
result["source_path"] = exercise.source_path;
|
||||
result["measures"] = static_cast<std::uint64_t>(exercise.measure_count);
|
||||
result["pages"] = static_cast<std::uint64_t>(exercise.total_pages);
|
||||
result["authored_key_signature"] = exercise.authored_key_signature;
|
||||
if (!exercise.variants.empty()) {
|
||||
auto const &primary = exercise.variants.front();
|
||||
result["key_signature"] = primary.key_signature;
|
||||
result["source_path"] = primary.source_path;
|
||||
result["measures"] = static_cast<std::uint64_t>(primary.measure_count);
|
||||
result["pages"] = static_cast<std::uint64_t>(primary.total_pages);
|
||||
}
|
||||
result["variant_count"] = static_cast<std::uint64_t>(exercise.variants.size());
|
||||
result["variants"] = std::move(variants);
|
||||
return result;
|
||||
}
|
||||
|
||||
auto lesson_json(vamp_zero::practice_lesson_group const &lesson) -> boost::json::object {
|
||||
auto lesson_json(vamp_zero::practice_lesson_group const &lesson, vamp_zero::practice_library const &library) -> boost::json::object {
|
||||
auto exercises = boost::json::array{};
|
||||
for (auto const &exercise : lesson.exercises) {
|
||||
exercises.push_back(exercise_json(exercise));
|
||||
exercises.push_back(exercise_json(library.exercises[exercise]));
|
||||
}
|
||||
auto result = boost::json::object{};
|
||||
result["id"] = lesson.id;
|
||||
@@ -222,10 +229,10 @@ auto practice_type_exercise_count(vamp_zero::practice_type_group const &type) ->
|
||||
return count;
|
||||
}
|
||||
|
||||
auto type_json(vamp_zero::practice_type_group const &type) -> boost::json::object {
|
||||
auto type_json(vamp_zero::practice_type_group const &type, vamp_zero::practice_library const &library) -> boost::json::object {
|
||||
auto lessons = boost::json::array{};
|
||||
for (auto const &lesson : type.lesson_groups) {
|
||||
lessons.push_back(lesson_json(lesson));
|
||||
lessons.push_back(lesson_json(lesson, library));
|
||||
}
|
||||
auto result = boost::json::object{};
|
||||
result["id"] = type.id;
|
||||
@@ -238,10 +245,10 @@ auto type_json(vamp_zero::practice_type_group const &type) -> boost::json::objec
|
||||
|
||||
auto performance_json(vamp_zero::app_state const &state) -> boost::json::object {
|
||||
auto groups = boost::json::array{};
|
||||
for (auto const &group : state.performance.groups) {
|
||||
for (auto const &group : state.catalog->performance.groups) {
|
||||
auto parts = boost::json::array{};
|
||||
for (auto const &part : group.parts) {
|
||||
parts.push_back(part_json(part));
|
||||
parts.push_back(part_json(state.catalog->performance.parts[part]));
|
||||
}
|
||||
auto item = boost::json::object{};
|
||||
item["title"] = group.title;
|
||||
@@ -250,19 +257,19 @@ auto performance_json(vamp_zero::app_state const &state) -> boost::json::object
|
||||
groups.push_back(std::move(item));
|
||||
}
|
||||
auto library = boost::json::object{};
|
||||
library["song_count"] = static_cast<std::uint64_t>(state.performance.groups.size());
|
||||
library["part_count"] = static_cast<std::uint64_t>(state.performance.parts.size());
|
||||
library["song_count"] = static_cast<std::uint64_t>(state.catalog->performance.groups.size());
|
||||
library["part_count"] = static_cast<std::uint64_t>(state.catalog->performance.parts.size());
|
||||
library["groups"] = std::move(groups);
|
||||
return library;
|
||||
}
|
||||
|
||||
auto practice_json(vamp_zero::app_state const &state) -> boost::json::object {
|
||||
auto types = boost::json::array{};
|
||||
for (auto const &type : state.practice.types) {
|
||||
types.push_back(type_json(type));
|
||||
for (auto const &type : state.catalog->practice.types) {
|
||||
types.push_back(type_json(type, state.catalog->practice));
|
||||
}
|
||||
auto exercises = boost::json::array{};
|
||||
for (auto const &exercise : state.practice.exercises) {
|
||||
for (auto const &exercise : state.catalog->practice.exercises) {
|
||||
exercises.push_back(exercise_json(exercise));
|
||||
}
|
||||
auto keys = boost::json::array{};
|
||||
@@ -275,10 +282,10 @@ auto practice_json(vamp_zero::app_state const &state) -> boost::json::object {
|
||||
selection["exercise_row_index"] = static_cast<std::uint64_t>(state.selected_practice_exercise_index);
|
||||
selection["key_row_index"] = static_cast<std::uint64_t>(state.selected_practice_key_index);
|
||||
if (auto const *type = selected_practice_type(state); type != nullptr) {
|
||||
selection["type"] = type_json(*type);
|
||||
selection["type"] = type_json(*type, state.catalog->practice);
|
||||
}
|
||||
if (auto const *lesson = selected_practice_lesson(state); lesson != nullptr) {
|
||||
selection["lesson_group"] = lesson_json(*lesson);
|
||||
selection["lesson_group"] = lesson_json(*lesson, state.catalog->practice);
|
||||
}
|
||||
if (auto const *exercise = selected_practice_exercise(state); exercise != nullptr) {
|
||||
selection["exercise"] = exercise_json(*exercise);
|
||||
@@ -299,8 +306,8 @@ auto practice_json(vamp_zero::app_state const &state) -> boost::json::object {
|
||||
}
|
||||
}
|
||||
auto practice = boost::json::object{};
|
||||
practice["type_count"] = static_cast<std::uint64_t>(state.practice.types.size());
|
||||
practice["exercise_count"] = static_cast<std::uint64_t>(state.practice.exercises.size());
|
||||
practice["type_count"] = static_cast<std::uint64_t>(state.catalog->practice.types.size());
|
||||
practice["exercise_count"] = static_cast<std::uint64_t>(state.catalog->practice.exercises.size());
|
||||
practice["types"] = std::move(types);
|
||||
practice["exercises"] = std::move(exercises);
|
||||
practice["key_count"] = static_cast<std::uint64_t>(vamp_zero::practice_key_names().size());
|
||||
@@ -368,11 +375,11 @@ auto vamp_zero::apply_app_command(vamp_zero::app_state state, vamp_protocol::pag
|
||||
return clamp_state(std::move(state));
|
||||
case vamp_zero::app_mode::PERFORMANCE_SONG_MENU:
|
||||
if (command == vamp_protocol::page_command::NEXT) {
|
||||
state.selected_song_index = wrap_next(state.selected_song_index, menu_row_count(state.performance.groups.size()));
|
||||
state.selected_song_index = wrap_next(state.selected_song_index, menu_row_count(state.catalog->performance.groups.size()));
|
||||
state.selected_part_index = 0;
|
||||
} else if (command == vamp_protocol::page_command::PREVIOUS) {
|
||||
state.selected_song_index =
|
||||
wrap_previous(state.selected_song_index, menu_row_count(state.performance.groups.size()));
|
||||
wrap_previous(state.selected_song_index, menu_row_count(state.catalog->performance.groups.size()));
|
||||
state.selected_part_index = 0;
|
||||
} else if (state.selected_song_index == 0U) {
|
||||
state.mode = vamp_zero::app_mode::MAIN_MENU;
|
||||
@@ -415,13 +422,13 @@ auto vamp_zero::apply_app_command(vamp_zero::app_state state, vamp_protocol::pag
|
||||
case vamp_zero::app_mode::PRACTICE_TYPE_MENU:
|
||||
if (command == vamp_protocol::page_command::NEXT) {
|
||||
state.selected_practice_type_index =
|
||||
wrap_next(state.selected_practice_type_index, menu_row_count(state.practice.types.size()));
|
||||
wrap_next(state.selected_practice_type_index, menu_row_count(state.catalog->practice.types.size()));
|
||||
state.selected_practice_lesson_index = 0;
|
||||
state.selected_practice_exercise_index = 0;
|
||||
state.selected_practice_key_index = 0;
|
||||
} else if (command == vamp_protocol::page_command::PREVIOUS) {
|
||||
state.selected_practice_type_index =
|
||||
wrap_previous(state.selected_practice_type_index, menu_row_count(state.practice.types.size()));
|
||||
wrap_previous(state.selected_practice_type_index, menu_row_count(state.catalog->practice.types.size()));
|
||||
state.selected_practice_lesson_index = 0;
|
||||
state.selected_practice_exercise_index = 0;
|
||||
state.selected_practice_key_index = 0;
|
||||
@@ -619,6 +626,9 @@ auto vamp_zero::remote_display_text(vamp_zero::app_state const &state) -> std::s
|
||||
}
|
||||
|
||||
auto vamp_zero::validate_app_state(vamp_zero::app_state const &state) -> std::expected<void, modulus::error> {
|
||||
if (!state.catalog) {
|
||||
return std::unexpected(vamp_zero::make_error(vamp_zero::error_code::INVALID_ARGUMENT, "catalogue is missing"));
|
||||
}
|
||||
if (state.selected_main_menu_index >= main_menu_count) {
|
||||
return std::unexpected(vamp_zero::make_error(vamp_zero::error_code::INVALID_ARGUMENT, "selected main menu index is out of range"));
|
||||
}
|
||||
@@ -638,14 +648,14 @@ auto vamp_zero::validate_app_state(vamp_zero::app_state const &state) -> std::ex
|
||||
if (state.audio.tempo_editing && state.mode != vamp_zero::app_mode::MAIN_MENU) {
|
||||
return std::unexpected(vamp_zero::make_error(vamp_zero::error_code::INVALID_ARGUMENT, "tempo edit mode requires the main menu"));
|
||||
}
|
||||
if (state.selected_song_index >= menu_row_count(state.performance.groups.size())) {
|
||||
if (state.selected_song_index >= menu_row_count(state.catalog->performance.groups.size())) {
|
||||
return std::unexpected(vamp_zero::make_error(vamp_zero::error_code::INVALID_ARGUMENT, "selected performance song row is out of range"));
|
||||
}
|
||||
if (auto const *group = selected_group(state);
|
||||
group != nullptr && state.selected_part_index >= menu_row_count(group->parts.size())) {
|
||||
return std::unexpected(vamp_zero::make_error(vamp_zero::error_code::INVALID_ARGUMENT, "selected performance part row is out of range"));
|
||||
}
|
||||
if (state.selected_practice_type_index >= menu_row_count(state.practice.types.size())) {
|
||||
if (state.selected_practice_type_index >= menu_row_count(state.catalog->practice.types.size())) {
|
||||
return std::unexpected(vamp_zero::make_error(vamp_zero::error_code::INVALID_ARGUMENT, "selected practice type row is out of range"));
|
||||
}
|
||||
if (auto const *type = selected_practice_type(state);
|
||||
@@ -668,7 +678,7 @@ auto vamp_zero::validate_app_state(vamp_zero::app_state const &state) -> std::ex
|
||||
if (state.mode == vamp_zero::app_mode::PRACTICE_KEY_MENU) {
|
||||
auto const *exercise = selected_practice_exercise(state);
|
||||
if (exercise == nullptr || !supports_key_selection(*exercise)) {
|
||||
return std::unexpected(vamp_zero::make_error(vamp_zero::error_code::INVALID_ARGUMENT, "practice key mode requires a melody exercise"));
|
||||
return std::unexpected(vamp_zero::make_error(vamp_zero::error_code::INVALID_ARGUMENT, "practice key mode requires an exercise with key variants"));
|
||||
}
|
||||
}
|
||||
if (state.mode == vamp_zero::app_mode::PERFORMANCE_SCORE) {
|
||||
|
||||
Reference in New Issue
Block a user