diff --git a/src/vamp_zero/score.cpp b/src/vamp_zero/score.cpp index c5617ef..72fb25f 100644 --- a/src/vamp_zero/score.cpp +++ b/src/vamp_zero/score.cpp @@ -84,9 +84,11 @@ constexpr auto thin_barline_thickness_spaces = std::float32_t{0.16F}; constexpr auto thick_barline_thickness_spaces = std::float32_t{0.50F}; constexpr auto tie_thickness_spaces = std::float32_t{0.13F}; constexpr auto normal_stem_length_spaces = std::float32_t{3.50F}; -constexpr auto preamble_vertical_correction_spaces = std::float32_t{0.50F}; -constexpr auto stem_head_horizontal_overlap_spaces = std::float32_t{0.06F}; -constexpr auto stem_head_vertical_overlap_spaces = std::float32_t{0.38F}; +constexpr auto clef_vertical_correction_spaces = std::float32_t{1.00F}; +constexpr auto key_signature_vertical_correction_spaces = std::float32_t{0.50F}; +constexpr auto time_signature_vertical_correction_spaces = std::float32_t{0.50F}; +constexpr auto stem_head_horizontal_overlap_spaces = std::float32_t{0.20F}; +constexpr auto stem_head_vertical_overlap_spaces = std::float32_t{0.45F}; constexpr auto measure_right_guard_spaces = std::float32_t{2.05F}; constexpr auto chord_above_staff_spaces = std::float32_t{3.65F}; constexpr auto chord_clearance_spaces = std::float32_t{0.45F}; @@ -923,7 +925,7 @@ auto layout_clef(vamp_zero::score_page_layout& layout, std::string_view clef, st auto reference_pitch = codepoint == glyph_f_clef ? vamp_zero::score_pitch{.letter = 'f', .octave = 3} : vamp_zero::score_pitch{.letter = 'g', .octave = 4}; - auto baseline_y = pitch_y(reference_pitch, staff_top, spacing, clef) + scaled(preamble_vertical_correction_spaces, spacing); + auto baseline_y = pitch_y(reference_pitch, staff_top, spacing, clef) + scaled(clef_vertical_correction_spaces, spacing); auto origin = origin_for_left_baseline(codepoint, x, baseline_y, spacing); add_glyph(layout, vamp_zero::score_layout_item_role::CLEF, codepoint, origin, spacing, score_ink(), system_index); return glyph_width(codepoint, spacing) + spacing * 0.90F; @@ -996,7 +998,7 @@ auto layout_key_signature( auto const total = static_cast(std::abs(count)); for (auto index = std::size_t{}; index < total; ++index) { auto pitch = key_signature_pitch(count, index, clef); - auto baseline_y = pitch_y(pitch, staff_top, spacing, clef) + scaled(preamble_vertical_correction_spaces, spacing); + auto baseline_y = pitch_y(pitch, staff_top, spacing, clef) + scaled(key_signature_vertical_correction_spaces, spacing); add_glyph( layout, vamp_zero::score_layout_item_role::KEY_SIGNATURE, @@ -1078,8 +1080,9 @@ auto layout_time_signature( if (width <= 0.0F) { return 0.0F; } - layout_time_signature_run(layout, numerator, x + (width - numerator_width) * 0.5F, staff_top + spacing * 1.5F, spacing, system_index); - layout_time_signature_run(layout, denominator, x + (width - denominator_width) * 0.5F, staff_top + spacing * 3.5F, spacing, system_index); + auto const vertical_correction = scaled(time_signature_vertical_correction_spaces, spacing); + layout_time_signature_run(layout, numerator, x + (width - numerator_width) * 0.5F, staff_top + spacing * 1.5F + vertical_correction, spacing, system_index); + layout_time_signature_run(layout, denominator, x + (width - denominator_width) * 0.5F, staff_top + spacing * 3.5F + vertical_correction, spacing, system_index); return width + spacing * 0.95F; } diff --git a/tests/test.cpp b/tests/test.cpp index 2c769f3..f3604b5 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -174,6 +174,10 @@ auto right_edge(vamp_zero::score_layout_item const& item) -> std::float32_t { return item.bounds.x + item.bounds.width; } +auto left_edge(vamp_zero::score_layout_item const& item) -> std::float32_t { + return item.bounds.x; +} + auto bottom_edge(vamp_zero::score_layout_item const& item) -> std::float32_t { return item.bounds.y + item.bounds.height; } @@ -182,6 +186,26 @@ auto near(std::float32_t left, std::float32_t right) -> std::bool_t { return std::abs(left - right) < 0.02F; } +void expect_up_stem_connected(vamp_zero::score_layout_item const& head, vamp_zero::score_layout_item const& stem, std::float32_t staff_spacing) { + auto const overlap = right_edge(head) - stem.from.x; + BOOST_TEST(overlap >= staff_spacing * 0.12F); + BOOST_TEST(overlap <= staff_spacing * 0.45F); + BOOST_TEST(stem.from.x > left_edge(head)); + BOOST_TEST(stem.from.y > head.bounds.y); + BOOST_TEST(stem.from.y < bottom_edge(head)); + BOOST_TEST(stem.to.y < stem.from.y); +} + +void expect_down_stem_connected(vamp_zero::score_layout_item const& head, vamp_zero::score_layout_item const& stem, std::float32_t staff_spacing) { + auto const overlap = stem.from.x - left_edge(head); + BOOST_TEST(overlap >= staff_spacing * 0.12F); + BOOST_TEST(overlap <= staff_spacing * 0.45F); + BOOST_TEST(stem.from.x < right_edge(head)); + BOOST_TEST(stem.from.y > head.bounds.y); + BOOST_TEST(stem.from.y < bottom_edge(head)); + BOOST_TEST(stem.to.y > stem.from.y); +} + auto test_database_config(std::filesystem::path const& path) -> vamp_zero::database_config { return { .path = path.string(), @@ -543,11 +567,11 @@ BOOST_AUTO_TEST_CASE(score_layout_orders_preamble_on_staff_baselines) { BOOST_TEST(clefs.front()->bounds.x < keys.front()->bounds.x); BOOST_TEST(keys.front()->bounds.x < times.front()->bounds.x); - BOOST_TEST(near(clefs.front()->origin.y, staff_lines.front()->from.y + layout.staff_spacing * 3.5F)); + BOOST_TEST(near(clefs.front()->origin.y, staff_lines.front()->from.y + layout.staff_spacing * 4.0F)); BOOST_TEST(near(keys.front()->origin.y, staff_lines.front()->from.y + layout.staff_spacing * 2.5F)); BOOST_REQUIRE_GE(times.size(), 2U); - BOOST_TEST(near(times[0]->origin.y, staff_lines.front()->from.y + layout.staff_spacing * 1.5F)); - BOOST_TEST(near(times[1]->origin.y, staff_lines.front()->from.y + layout.staff_spacing * 3.5F)); + BOOST_TEST(near(times[0]->origin.y, staff_lines.front()->from.y + layout.staff_spacing * 2.0F)); + BOOST_TEST(near(times[1]->origin.y, staff_lines.front()->from.y + layout.staff_spacing * 4.0F)); } BOOST_AUTO_TEST_CASE(score_system_ranges_force_breaks_before_key_changes) { @@ -627,19 +651,29 @@ BOOST_AUTO_TEST_CASE(score_page_count_uses_forced_notation_breaks) { } BOOST_AUTO_TEST_CASE(score_layout_attaches_stems_to_notehead_anchors) { - auto score = score_with_notes({note({pitch('d', "n")})}); - auto layout = vamp_zero::layout_score_page({.x = 0.0F, .y = 0.0F, .width = 976.0F, .height = 484.0F}, score, 0U); + auto up_score = score_with_notes({note({pitch('d', "n")})}); + auto up_layout = vamp_zero::layout_score_page({.x = 0.0F, .y = 0.0F, .width = 976.0F, .height = 484.0F}, up_score, 0U); + auto up_heads = layout_items(up_layout, vamp_zero::score_layout_item_role::NOTEHEAD, 0U, 0U, 0U); + auto up_stems = layout_items(up_layout, vamp_zero::score_layout_item_role::STEM, 0U, 0U, 0U); + BOOST_REQUIRE_EQUAL(up_heads.size(), 1U); + BOOST_REQUIRE_EQUAL(up_stems.size(), 1U); + expect_up_stem_connected(*up_heads.front(), *up_stems.front(), up_layout.staff_spacing); - auto heads = layout_items(layout, vamp_zero::score_layout_item_role::NOTEHEAD, 0U, 0U, 0U); - auto stems = layout_items(layout, vamp_zero::score_layout_item_role::STEM, 0U, 0U, 0U); - BOOST_REQUIRE_EQUAL(heads.size(), 1U); - BOOST_REQUIRE_EQUAL(stems.size(), 1U); + auto down_score = score_with_notes({note({pitch('c', "n", 6)})}); + auto down_layout = vamp_zero::layout_score_page({.x = 0.0F, .y = 0.0F, .width = 976.0F, .height = 484.0F}, down_score, 0U); + auto down_heads = layout_items(down_layout, vamp_zero::score_layout_item_role::NOTEHEAD, 0U, 0U, 0U); + auto down_stems = layout_items(down_layout, vamp_zero::score_layout_item_role::STEM, 0U, 0U, 0U); + BOOST_REQUIRE_EQUAL(down_heads.size(), 1U); + BOOST_REQUIRE_EQUAL(down_stems.size(), 1U); + expect_down_stem_connected(*down_heads.front(), *down_stems.front(), down_layout.staff_spacing); - BOOST_TEST(stems.front()->from.x < heads.front()->bounds.x + heads.front()->bounds.width); - BOOST_TEST(stems.front()->from.x > heads.front()->bounds.x + heads.front()->bounds.width - layout.staff_spacing * 0.25F); - BOOST_TEST(stems.front()->from.y > heads.front()->bounds.y); - BOOST_TEST(stems.front()->from.y < heads.front()->bounds.y + heads.front()->bounds.height); - BOOST_TEST(stems.front()->to.y < stems.front()->from.y); + auto half_score = score_with_notes({note_with_ticks({pitch('d', "n")}, 8192)}); + auto half_layout = vamp_zero::layout_score_page({.x = 0.0F, .y = 0.0F, .width = 976.0F, .height = 484.0F}, half_score, 0U); + auto half_heads = layout_items(half_layout, vamp_zero::score_layout_item_role::NOTEHEAD, 0U, 0U, 0U); + auto half_stems = layout_items(half_layout, vamp_zero::score_layout_item_role::STEM, 0U, 0U, 0U); + BOOST_REQUIRE_EQUAL(half_heads.size(), 1U); + BOOST_REQUIRE_EQUAL(half_stems.size(), 1U); + expect_up_stem_connected(*half_heads.front(), *half_stems.front(), half_layout.staff_spacing); } BOOST_AUTO_TEST_CASE(score_layout_displaces_chord_seconds_and_columns_accidentals) {