X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fbeam.cc;h=a9a19b38c72fae30731caa1f58dea78b65499a6d;hb=47db9a3883d726ca53e2133a3b2298f78dd6a32e;hp=ea92315939ca653fe53c9ca347a6ede93d5a3c50;hpb=0c61221b46addec50e2406e04af44a7d460443d4;p=lilypond.git diff --git a/lily/beam.cc b/lily/beam.cc index ea92315939..a9a19b38c7 100644 --- a/lily/beam.cc +++ b/lily/beam.cc @@ -1,7 +1,7 @@ /* This file is part of LilyPond, the GNU music typesetter. - Copyright (C) 1997--2011 Han-Wen Nienhuys + Copyright (C) 1997--2015 Han-Wen Nienhuys Jan Nieuwenhuizen LilyPond is free software: you can redistribute it and/or modify @@ -37,6 +37,7 @@ #include "beam.hh" +#include "axis-group-interface.hh" #include "align-interface.hh" #include "beam-scoring-problem.hh" #include "beaming-pattern.hh" @@ -144,11 +145,11 @@ MAKE_SCHEME_CALLBACK (Beam, calc_normal_stems, 1); SCM Beam::calc_normal_stems (SCM smob) { - Grob *me = unsmob_grob (smob); + Grob *me = Grob::unsmob (smob); extract_grob_set (me, "stems", stems); SCM val = Grob_array::make_array (); - Grob_array *ga = unsmob_grob_array (val); + Grob_array *ga = Grob_array::unsmob (val); for (vsize i = 0; i < stems.size (); i++) if (Stem::is_normal_stem (stems[i])) ga->add (stems[i]); @@ -160,7 +161,7 @@ MAKE_SCHEME_CALLBACK (Beam, calc_direction, 1); SCM Beam::calc_direction (SCM smob) { - Grob *me = unsmob_grob (smob); + Grob *me = Grob::unsmob (smob); /* Beams with less than 2 two stems don't make much sense, but could happen when you do @@ -196,6 +197,18 @@ Beam::calc_direction (SCM smob) dir = to_dir (stem->get_property_data ("direction")); else dir = to_dir (stem->get_property ("default-direction")); + + extract_grob_set (stem, "note-heads", heads); + /* default position of Kievan heads with beams is down + placing this here avoids warnings downstream */ + if (heads.size()) + { + if (heads[0]->get_property ("style") == ly_symbol2scm ("kievan")) + { + if (dir == CENTER) + dir = DOWN; + } + } } } @@ -261,7 +274,7 @@ MAKE_SCHEME_CALLBACK (Beam, calc_beaming, 1) SCM Beam::calc_beaming (SCM smob) { - Grob *me = unsmob_grob (smob); + Grob *me = Grob::unsmob (smob); extract_grob_set (me, "stems", stems); @@ -283,9 +296,8 @@ Beam::calc_beaming (SCM smob) last_dir ? last_dir : this_dir, this_dir); - Direction d = LEFT; Slice new_slice; - do + for (LEFT_and_RIGHT (d)) { new_slice.set_empty (); SCM s = index_get_cell (this_beaming, d); @@ -298,7 +310,6 @@ Beam::calc_beaming (SCM smob) scm_set_car_x (s, scm_from_int (new_beam_pos)); } } - while (flip (&d) != LEFT); if (!new_slice.is_empty ()) last_int = new_slice; @@ -342,7 +353,7 @@ Beam::calc_beam_segments (SCM smob) { /* ugh, this has a side-effect that we need to ensure that Stem #'beaming is correct */ - Grob *me_grob = unsmob_grob (smob); + Grob *me_grob = Grob::unsmob (smob); (void) me_grob->get_property ("beaming"); Spanner *me = dynamic_cast (me_grob); @@ -350,10 +361,8 @@ Beam::calc_beam_segments (SCM smob) extract_grob_set (me, "stems", stems); Grob *commonx = common_refpoint_of_array (stems, me, X_AXIS); - Direction d = LEFT; - do + for (LEFT_and_RIGHT (d)) commonx = me->get_bound (d)->common_refpoint (commonx, X_AXIS); - while (flip (&d) != LEFT); int gap_count = robust_scm2int (me->get_property ("gap-count"), 0); Real gap_length = robust_scm2double (me->get_property ("gap"), 0.0); @@ -375,7 +384,7 @@ Beam::calc_beam_segments (SCM smob) Real stem_x = stem->relative_coordinate (commonx, X_AXIS); SCM beaming = stem->get_property ("beaming"); - do + for (LEFT_and_RIGHT (d)) { // Find the maximum and minimum beam ranks. // Given that RANKS is never reset to empty, the interval will always be @@ -414,7 +423,6 @@ Beam::calc_beam_segments (SCM smob) stem_segments[beam_rank].push_back (seg); } } - while (flip (&d) != LEFT); } Drul_array break_overshoot @@ -443,9 +451,8 @@ Beam::calc_beam_segments (SCM smob) // we are currently looking at (ie. if segs[j].dir_ == event_dir then we // are looking at that edge of the beam segment that is furthest from its // stem). - Direction event_dir = LEFT; Beam_stem_segment const &seg = segs[j]; - do + for (LEFT_and_RIGHT (event_dir)) { Beam_stem_segment const &neighbor_seg = segs[j + event_dir]; // TODO: make names clearer? --jneem @@ -483,8 +490,8 @@ Beam::calc_beam_segments (SCM smob) && me->get_bound (event_dir)->break_status_dir ()) { current.horizontal_[event_dir] - = (robust_relative_extent (me->get_bound (event_dir), - commonx, X_AXIS)[RIGHT] + = (Axis_group_interface::generic_bound_extent (me->get_bound (event_dir), + commonx, X_AXIS)[RIGHT] + event_dir * break_overshoot[event_dir]); } else @@ -541,22 +548,19 @@ Beam::calc_beam_segments (SCM smob) current = Beam_segment (); } } - while (flip (&event_dir) != LEFT); } } SCM segments_scm = SCM_EOL; - SCM *tail = &segments_scm; - for (vsize i = 0; i < segments.size (); i++) + for (vsize i = segments.size (); i--;) { - *tail = scm_cons (scm_list_2 (scm_cons (ly_symbol2scm ("vertical-count"), - scm_from_int (segments[i].vertical_count_)), - scm_cons (ly_symbol2scm ("horizontal"), - ly_interval2scm (segments[i].horizontal_))), - SCM_EOL); - tail = SCM_CDRLOC (*tail); + segments_scm = scm_cons (scm_list_2 (scm_cons (ly_symbol2scm ("vertical-count"), + scm_from_int (segments[i].vertical_count_)), + scm_cons (ly_symbol2scm ("horizontal"), + ly_interval2scm (segments[i].horizontal_))), + segments_scm); } return segments_scm; @@ -566,7 +570,7 @@ MAKE_SCHEME_CALLBACK (Beam, calc_x_positions, 1); SCM Beam::calc_x_positions (SCM smob) { - Spanner *me = unsmob_spanner (smob); + Spanner *me = Spanner::unsmob (smob); SCM segments = me->get_property ("beam-segments"); Interval x_positions; x_positions.set_empty (); @@ -582,10 +586,8 @@ Beam::calc_x_positions (SCM smob) { extract_grob_set (me, "stems", stems); Grob *common_x = common_refpoint_of_array (stems, me, X_AXIS); - Direction d = LEFT; - do + for (LEFT_and_RIGHT (d)) x_positions[d] = me->relative_coordinate (common_x, X_AXIS); - while (flip (&d) != LEFT); } return ly_interval2scm (x_positions); } @@ -609,7 +611,7 @@ MAKE_SCHEME_CALLBACK (Beam, print, 1); SCM Beam::print (SCM grob) { - Spanner *me = unsmob_spanner (grob); + Spanner *me = Spanner::unsmob (grob); /* TODO - mild code dup for all the commonx calls. Some use just common_refpoint_of_array, some (in print and @@ -620,10 +622,8 @@ Beam::print (SCM grob) */ extract_grob_set (me, "stems", stems); Grob *commonx = common_refpoint_of_array (stems, me, X_AXIS); - Direction d = LEFT; - do + for (LEFT_and_RIGHT (d)) commonx = me->get_bound (d)->common_refpoint (commonx, X_AXIS); - while (flip (&d) != LEFT); vector segments = get_beam_segments (me); @@ -656,9 +656,9 @@ Beam::print (SCM grob) Interval placements = robust_scm2interval (me->get_property ("normalized-endpoints"), Interval (0.0, 0.0)); Stencil the_beam; - int extreme = (segments[0].vertical_count_ == 0 - ? segments[0].vertical_count_ - : segments.back ().vertical_count_); + vsize extreme = (segments[0].vertical_count_ == 0 + ? segments[0].vertical_count_ + : segments.back ().vertical_count_); for (vsize i = 0; i < segments.size (); i++) { @@ -685,7 +685,7 @@ Beam::print (SCM grob) // we need two translations: the normal one and // the one of the lowest segment - int idx[] = {i, extreme}; + size_t idx[] = {i, extreme}; Real translations[2]; for (int j = 0; j < 2; j++) @@ -739,7 +739,7 @@ Beam::print (SCM grob) Direction stem_dir = stems.size () ? to_dir (stems[0]->get_property ("direction")) : UP; - Stencil score = *unsmob_stencil (Text_interface::interpret_markup + Stencil score = *Stencil::unsmob (Text_interface::interpret_markup (me->layout ()->self_scm (), properties, annotation)); if (!score.is_empty ()) @@ -763,13 +763,11 @@ Beam::get_default_dir (Grob *me) for (iterof (s, stems); s != stems.end (); s++) { Interval positions = Stem::head_positions (*s); - Direction d = DOWN; - do + for (DOWN_and_UP (d)) { if (sign (positions[d]) == d) extremes[d] = d * max (d * positions[d], d * extremes[d]); } - while (flip (&d) != DOWN); } Drul_array total (0, 0); @@ -860,9 +858,7 @@ Beam::consider_auto_knees (Grob *me) if (!scm_is_number (scm)) return; - Interval_set gaps; - - gaps.set_full (); + vector forbidden_intervals; extract_grob_set (me, "normal-stems", stems); @@ -896,15 +892,17 @@ Beam::consider_auto_knees (Grob *me) } head_extents_array.push_back (head_extents); - gaps.remove_interval (head_extents); + forbidden_intervals.push_back (head_extents); } Interval max_gap; Real max_gap_len = 0.0; - for (vsize i = gaps.allowed_regions_.size () - 1; i != VPOS; i--) + vector allowed_regions + = Interval_set::interval_union (forbidden_intervals).complement ().intervals (); + for (vsize i = allowed_regions.size () - 1; i != VPOS; i--) { - Interval gap = gaps.allowed_regions_[i]; + Interval gap = allowed_regions[i]; /* the outer gaps are not knees. @@ -949,7 +947,7 @@ MAKE_SCHEME_CALLBACK (Beam, calc_stem_shorten, 1) SCM Beam::calc_stem_shorten (SCM smob) { - Grob *me = unsmob_grob (smob); + Grob *me = Grob::unsmob (smob); /* shortening looks silly for x staff beams @@ -984,7 +982,7 @@ MAKE_SCHEME_CALLBACK (Beam, quanting, 3); SCM Beam::quanting (SCM smob, SCM ys_scm, SCM align_broken_intos) { - Grob *me = unsmob_grob (smob); + Grob *me = Grob::unsmob (smob); Drul_array ys = robust_scm2drul (ys_scm, Drul_array (infinity_f, -infinity_f)); bool cbs = to_boolean (align_broken_intos); @@ -1066,7 +1064,7 @@ MAKE_SCHEME_CALLBACK (Beam, set_stem_lengths, 1); SCM Beam::set_stem_lengths (SCM smob) { - Grob *me = unsmob_grob (smob); + Grob *me = Grob::unsmob (smob); /* trigger callbacks. */ (void) me->get_property ("direction"); @@ -1132,13 +1130,12 @@ Beam::set_beaming (Grob *me, Beaming_pattern const *beaming) { extract_grob_set (me, "stems", stems); - Direction d = LEFT; for (vsize i = 0; i < stems.size (); i++) { /* Don't overwrite user settings. */ - do + for (LEFT_and_RIGHT (d)) { Grob *stem = stems[i]; SCM beaming_prop = stem->get_property ("beaming"); @@ -1160,7 +1157,6 @@ Beam::set_beaming (Grob *me, Beaming_pattern const *beaming) Stem::set_beaming (stem, count, d); } } - while (flip (&d) != LEFT); } } @@ -1221,25 +1217,30 @@ MAKE_SCHEME_CALLBACK_WITH_OPTARGS (Beam, rest_collision_callback, 2, 1, ""); SCM Beam::rest_collision_callback (SCM smob, SCM prev_offset) { - Grob *rest = unsmob_grob (smob); + Grob *rest = Grob::unsmob (smob); if (scm_is_number (rest->get_property ("staff-position"))) return scm_from_int (0); Real offset = robust_scm2double (prev_offset, 0.0); - Grob *st = unsmob_grob (rest->get_object ("stem")); + Grob *st = Grob::unsmob (rest->get_object ("stem")); Grob *stem = st; if (!stem) return scm_from_double (0.0); - Grob *beam = unsmob_grob (stem->get_object ("beam")); + Grob *beam = Grob::unsmob (stem->get_object ("beam")); if (!beam || !Beam::has_interface (beam) || !Beam::normal_stem_count (beam)) return scm_from_double (0.0); + Grob *common_y = rest->common_refpoint (beam, Y_AXIS); + Drul_array pos (robust_scm2drul (beam->get_property ("positions"), Drul_array (0, 0))); + for (LEFT_and_RIGHT (dir)) + pos[dir] += beam->relative_coordinate (common_y, Y_AXIS); + Real staff_space = Staff_symbol_referencer::staff_space (rest); scale_drul (&pos, staff_space); @@ -1272,8 +1273,6 @@ Beam::rest_collision_callback (SCM smob, SCM prev_offset) + (beam_count - 1) * beam_translation; Real beam_y = stem_y - d * height_of_my_beams; - Grob *common_y = rest->common_refpoint (beam, Y_AXIS); - Interval rest_extent = rest->extent (rest, Y_AXIS); rest_extent.translate (offset + rest->get_parent (Y_AXIS)->relative_coordinate (common_y, Y_AXIS)); @@ -1285,51 +1284,46 @@ Beam::rest_collision_callback (SCM smob, SCM prev_offset) Real shift = d * min (d * (beam_y - d * minimum_distance - rest_dim), 0.0); shift /= staff_space; - Real rad = Staff_symbol_referencer::line_count (rest) * staff_space / 2; /* Always move discretely by half spaces */ shift = ceil (fabs (shift * 2.0)) / 2.0 * sign (shift); + Interval staff_span = Staff_symbol_referencer::staff_span (rest); + staff_span *= staff_space / 2; + /* Inside staff, move by whole spaces*/ - if ((rest_extent[d] + staff_space * shift) * d - < rad - || (rest_extent[-d] + staff_space * shift) * -d - < rad) + if (staff_span.contains (rest_extent[d] + staff_space * shift) + || staff_span.contains (rest_extent[-d] + staff_space * shift)) shift = ceil (fabs (shift)) * sign (shift); return scm_from_double (offset + staff_space * shift); } +/* + Estimate the position of a rest under a beam, + using the average position of its neighboring heads. +*/ MAKE_SCHEME_CALLBACK_WITH_OPTARGS (Beam, pure_rest_collision_callback, 4, 1, ""); SCM Beam::pure_rest_collision_callback (SCM smob, - SCM, /* prev_offset */ SCM, /* start */ - SCM /* end */) + SCM, /* end */ + SCM prev_offset) { - Real amount = 0.0; + Real previous = robust_scm2double (prev_offset, 0.0); - Grob *me = unsmob_grob (smob); - Grob *stem = unsmob_grob (me->get_object ("stem")); + Grob *me = Grob::unsmob (smob); + Grob *stem = Grob::unsmob (me->get_object ("stem")); if (!stem) - return scm_from_double (amount); - Grob *beam = unsmob_grob (stem->get_object ("beam")); + return scm_from_double (previous); + Grob *beam = Grob::unsmob (stem->get_object ("beam")); if (!beam - || !Beam::normal_stem_count (beam)) - return scm_from_double (amount); + || !Beam::normal_stem_count (beam) + || !is_direction (beam->get_property_data ("direction"))) + return scm_from_double (previous); Real ss = Staff_symbol_referencer::staff_space (me); - /* - This gives the extrema of rest positions. - In general, beams are never typeset more than one staff space away - from the staff in either direction. - */ - Grob *staff = Staff_symbol_referencer::get_staff_symbol (me); - Interval rest_max_pos = staff ? Staff_symbol::line_span (staff) : Interval (0.0, 0.0); - rest_max_pos.widen (1); - rest_max_pos *= ss / 2; - extract_grob_set (beam, "stems", stems); vector my_stems; @@ -1349,7 +1343,7 @@ Beam::pure_rest_collision_callback (SCM smob, Grob *right; if (idx == (vsize) - 1 || my_stems.size () == 1) - return scm_from_double (amount); + return scm_from_double (previous); else if (idx == 0) left = right = my_stems[1]; else if (idx == my_stems.size () - 1) @@ -1359,15 +1353,27 @@ Beam::pure_rest_collision_callback (SCM smob, left = my_stems[idx - 1]; right = my_stems[idx + 1]; } + + /* Estimate the closest beam to be four positions away from the heads, */ Direction beamdir = get_grob_direction (beam); - /* - Take the position between the two bounding head_positions, - then bound it by the minimum and maximum positions outside the staff. - 4.0 = 2.0 to get out of staff space * 2.0 for the average - */ - amount = min (max ((Stem::head_positions (left)[beamdir] + Stem::head_positions (right)[beamdir]) / 4.0, rest_max_pos[DOWN]), rest_max_pos[UP]); + Real beam_pos = (Stem::head_positions (left)[beamdir] + + Stem::head_positions (right)[beamdir]) / 2.0 + + 4.0 * beamdir; // four staff-positions + /* and that the closest beam never crosses staff center by more than two positions */ + beam_pos = max (-2.0, beam_pos * beamdir) * beamdir; + + Real minimum_distance + = ss * (robust_scm2double (stem->get_property ("stemlet-length"), 0.0) + + robust_scm2double (me->get_property ("minimum-distance"), 0.0)); + Real offset = beam_pos * ss / 2.0 + - minimum_distance * beamdir + - me->extent (me, Y_AXIS)[beamdir]; + + /* Always move by a whole number of staff spaces, always away from the beam */ + offset = floor (min (0.0, (offset - previous) / ss * beamdir)) + * ss * beamdir + previous; - return scm_from_double (amount); + return scm_from_double (offset); } bool @@ -1411,7 +1417,7 @@ MAKE_SCHEME_CALLBACK (Beam, calc_cross_staff, 1) SCM Beam::calc_cross_staff (SCM smob) { - return scm_from_bool (is_cross_staff (unsmob_grob (smob))); + return scm_from_bool (is_cross_staff (Grob::unsmob (smob))); } int