X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fbeam.cc;h=a50f2904bc0b00e4a497c16c908b13cabf38d96b;hb=a6a51abfd0195a3cf7d6ea095cf69808852f21ce;hp=4e48d437392efccd7232804f37fea0cd120cfd02;hpb=16ac0db39d8cca1de68ce79154386764172aca10;p=lilypond.git diff --git a/lily/beam.cc b/lily/beam.cc index 4e48d43739..a50f2904bc 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--2012 Han-Wen Nienhuys + Copyright (C) 1997--2015 Han-Wen Nienhuys Jan Nieuwenhuizen LilyPond is free software: you can redistribute it and/or modify @@ -119,11 +119,13 @@ Beam::get_beam_translation (Grob *me) Real beam_thickness = get_beam_thickness (me); Real fract = robust_scm2double (me->get_property ("length-fraction"), 1.0); - Real beam_translation = beam_count < 4 - ? (2 * staff_space + line - beam_thickness) / 2.0 - : (3 * staff_space + line - beam_thickness) / 3.0; - - return fract * beam_translation; + /* + if fract != 1.0, as is the case for grace notes, we want the gap + to decrease too. To achieve this, we divide the thickness by + fract */ + return (beam_count < 4 + ? (2 * staff_space * fract + line * fract - beam_thickness) / 2.0 + : (3 * staff_space * fract + line * fract - beam_thickness) / 3.0); } /* Maximum beam_count. */ @@ -145,11 +147,11 @@ MAKE_SCHEME_CALLBACK (Beam, calc_normal_stems, 1); SCM Beam::calc_normal_stems (SCM smob) { - Grob *me = unsmob_grob (smob); + Grob *me = unsmob (smob); extract_grob_set (me, "stems", stems); SCM val = Grob_array::make_array (); - Grob_array *ga = unsmob_grob_array (val); + Grob_array *ga = unsmob (val); for (vsize i = 0; i < stems.size (); i++) if (Stem::is_normal_stem (stems[i])) ga->add (stems[i]); @@ -161,7 +163,7 @@ MAKE_SCHEME_CALLBACK (Beam, calc_direction, 1); SCM Beam::calc_direction (SCM smob) { - Grob *me = unsmob_grob (smob); + Grob *me = unsmob (smob); /* Beams with less than 2 two stems don't make much sense, but could happen when you do @@ -197,6 +199,19 @@ 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 (scm_is_eq (heads[0]->get_property ("style"), + ly_symbol2scm ("kievan"))) + { + if (dir == CENTER) + dir = DOWN; + } + } } } @@ -244,7 +259,7 @@ position_with_maximal_common_beams (SCM left_beaming, SCM right_beaming, for (SCM s = scm_car (right_beaming); scm_is_pair (s); s = scm_cdr (s)) { int k = -right_dir * scm_to_int (scm_car (s)) + i; - if (scm_c_memq (scm_from_int (k), left_beaming) != SCM_BOOL_F) + if (scm_is_true (ly_memv (scm_from_int (k), left_beaming))) count++; } @@ -262,7 +277,7 @@ MAKE_SCHEME_CALLBACK (Beam, calc_beaming, 1) SCM Beam::calc_beaming (SCM smob) { - Grob *me = unsmob_grob (smob); + Grob *me = unsmob (smob); extract_grob_set (me, "stems", stems); @@ -284,9 +299,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); @@ -299,7 +313,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; @@ -343,7 +356,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 = unsmob (smob); (void) me_grob->get_property ("beaming"); Spanner *me = dynamic_cast (me_grob); @@ -351,10 +364,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); @@ -376,7 +387,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 @@ -415,7 +426,6 @@ Beam::calc_beam_segments (SCM smob) stem_segments[beam_rank].push_back (seg); } } - while (flip (&d) != LEFT); } Drul_array break_overshoot @@ -444,9 +454,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 @@ -542,22 +551,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; @@ -567,7 +573,7 @@ MAKE_SCHEME_CALLBACK (Beam, calc_x_positions, 1); SCM Beam::calc_x_positions (SCM smob) { - Spanner *me = unsmob_spanner (smob); + Spanner *me = unsmob (smob); SCM segments = me->get_property ("beam-segments"); Interval x_positions; x_positions.set_empty (); @@ -583,10 +589,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); } @@ -610,7 +614,7 @@ MAKE_SCHEME_CALLBACK (Beam, print, 1); SCM Beam::print (SCM grob) { - Spanner *me = unsmob_spanner (grob); + Spanner *me = unsmob (grob); /* TODO - mild code dup for all the commonx calls. Some use just common_refpoint_of_array, some (in print and @@ -621,10 +625,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); @@ -657,9 +659,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++) { @@ -686,7 +688,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++) @@ -740,7 +742,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 = *unsmob (Text_interface::interpret_markup (me->layout ()->self_scm (), properties, annotation)); if (!score.is_empty ()) @@ -764,13 +766,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); @@ -861,9 +861,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); @@ -875,11 +873,11 @@ Beam::consider_auto_knees (Grob *me) { Grob *stem = stems[i]; - Interval head_extents = Stem::head_positions (stem); - if (!head_extents.is_empty ()) + Interval head_extents; + if (Stem::head_count (stem)) { - head_extents[LEFT] += -1; - head_extents[RIGHT] += 1; + head_extents = Stem::head_positions (stem); + head_extents.widen (1); head_extents *= staff_space * 0.5; /* @@ -897,15 +895,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. @@ -950,7 +950,7 @@ MAKE_SCHEME_CALLBACK (Beam, calc_stem_shorten, 1) SCM Beam::calc_stem_shorten (SCM smob) { - Grob *me = unsmob_grob (smob); + Grob *me = unsmob (smob); /* shortening looks silly for x staff beams @@ -964,7 +964,7 @@ Beam::calc_stem_shorten (SCM smob) int beam_count = get_beam_count (me); SCM shorten_list = me->get_property ("beamed-stem-shorten"); - if (shorten_list == SCM_EOL) + if (scm_is_null (shorten_list)) return scm_from_int (0); Real staff_space = Staff_symbol_referencer::staff_space (me); @@ -985,7 +985,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 = unsmob (smob); Drul_array ys = robust_scm2drul (ys_scm, Drul_array (infinity_f, -infinity_f)); bool cbs = to_boolean (align_broken_intos); @@ -1006,7 +1006,7 @@ where_are_the_whole_beams (SCM beaming) for (SCM s = scm_car (beaming); scm_is_pair (s); s = scm_cdr (s)) { - if (scm_c_memq (scm_car (s), scm_cdr (beaming)) != SCM_BOOL_F) + if (scm_is_true (ly_memv (scm_car (s), scm_cdr (beaming)))) l.add_point (scm_to_int (scm_car (s))); } @@ -1067,7 +1067,7 @@ MAKE_SCHEME_CALLBACK (Beam, set_stem_lengths, 1); SCM Beam::set_stem_lengths (SCM smob) { - Grob *me = unsmob_grob (smob); + Grob *me = unsmob (smob); /* trigger callbacks. */ (void) me->get_property ("direction"); @@ -1133,18 +1133,17 @@ 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"); - if (beaming_prop == SCM_EOL - || index_get_cell (beaming_prop, d) == SCM_EOL) + if (scm_is_null (beaming_prop) + || scm_is_null (index_get_cell (beaming_prop, d))) { int count = beaming->beamlet_count (i, d); if (i > 0 @@ -1161,7 +1160,6 @@ Beam::set_beaming (Grob *me, Beaming_pattern const *beaming) Stem::set_beaming (stem, count, d); } } - while (flip (&d) != LEFT); } } @@ -1222,31 +1220,31 @@ 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); + if (!scm_is_number (prev_offset)) + prev_offset = SCM_INUM0; + + Grob *rest = unsmob (smob); if (scm_is_number (rest->get_property ("staff-position"))) - return scm_from_int (0); + return prev_offset; - Real offset = robust_scm2double (prev_offset, 0.0); + Grob *stem = unsmob (rest->get_object ("stem")); - Grob *st = unsmob_grob (rest->get_object ("stem")); - Grob *stem = st; if (!stem) - return scm_from_double (0.0); - Grob *beam = unsmob_grob (stem->get_object ("beam")); + return prev_offset; + + Grob *beam = unsmob (stem->get_object ("beam")); if (!beam - || !Beam::has_interface (beam) + || !has_interface (beam) || !Beam::normal_stem_count (beam)) - return scm_from_double (0.0); + return prev_offset; Grob *common_y = rest->common_refpoint (beam, Y_AXIS); Drul_array pos (robust_scm2drul (beam->get_property ("positions"), Drul_array (0, 0))); - Direction dir = LEFT; - do + for (LEFT_and_RIGHT (dir)) pos[dir] += beam->relative_coordinate (common_y, Y_AXIS); - while (flip (&dir) != LEFT); Real staff_space = Staff_symbol_referencer::staff_space (rest); @@ -1280,9 +1278,9 @@ Beam::rest_collision_callback (SCM smob, SCM prev_offset) + (beam_count - 1) * beam_translation; Real beam_y = stem_y - d * height_of_my_beams; - + Real offset = robust_scm2double (prev_offset, 0.0); Interval rest_extent = rest->extent (rest, Y_AXIS); - rest_extent.translate (offset + rest->get_parent (Y_AXIS)->relative_coordinate (common_y, Y_AXIS)); + rest_extent.translate (offset + rest->parent_relative (common_y, Y_AXIS)); Real rest_dim = rest_extent[d]; Real minimum_distance @@ -1292,52 +1290,47 @@ 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; + if (!scm_is_number (prev_offset)) + prev_offset = SCM_INUM0; - Grob *me = unsmob_grob (smob); - Grob *stem = unsmob_grob (me->get_object ("stem")); + Grob *me = unsmob (smob); + Grob *stem = unsmob (me->get_object ("stem")); if (!stem) - return scm_from_double (amount); - Grob *beam = unsmob_grob (stem->get_object ("beam")); + return prev_offset; + Grob *beam = unsmob (stem->get_object ("beam")); if (!beam || !Beam::normal_stem_count (beam) || !is_direction (beam->get_property_data ("direction"))) - return scm_from_double (amount); + return prev_offset; 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; @@ -1357,7 +1350,7 @@ Beam::pure_rest_collision_callback (SCM smob, Grob *right; if (idx == (vsize) - 1 || my_stems.size () == 1) - return scm_from_double (amount); + return prev_offset; else if (idx == 0) left = right = my_stems[1]; else if (idx == my_stems.size () - 1) @@ -1367,15 +1360,28 @@ 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; - return scm_from_double (amount); + 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]; + Real previous = robust_scm2double (prev_offset, 0.0); + + /* 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 (offset); } bool @@ -1419,7 +1425,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 (unsmob (smob))); } int