X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fbeam.cc;h=183a936440ff12fe7038025671431264a7ae7ae3;hb=0ab23da42c693f35581f0cd36ae0df93d1e3e0d9;hp=9dd66cef9a4124658bf447b14d81dc1f9ecac1d1;hpb=7693db10b018da89a3123cb4c9e21e3956638c56;p=lilypond.git diff --git a/lily/beam.cc b/lily/beam.cc index 9dd66cef9a..183a936440 100644 --- a/lily/beam.cc +++ b/lily/beam.cc @@ -3,7 +3,7 @@ source file of the GNU LilyPond music typesetter - (c) 1997--2006 Han-Wen Nienhuys + (c) 1997--2007 Han-Wen Nienhuys Jan Nieuwenhuizen */ @@ -41,6 +41,7 @@ #include "staff-symbol-referencer.hh" #include "stem.hh" #include "warn.hh" +#include "grob-array.hh" #if DEBUG_BEAM_SCORING #include "text-interface.hh" // debug output. @@ -119,6 +120,21 @@ Beam::get_beam_count (Grob *me) return m; } +MAKE_SCHEME_CALLBACK (Beam, calc_normal_stems, 1); +SCM +Beam::calc_normal_stems (SCM smob) +{ + Grob *me = unsmob_grob (smob); + + extract_grob_set (me, "stems", stems); + SCM val = Grob_array::make_array (); + Grob_array *ga = unsmob_grob_array (val); + for (vsize i = 0; i < stems.size (); i++) + if (Stem::is_normal_stem (stems[i])) + ga->add (stems[i]); + + return val; +} MAKE_SCHEME_CALLBACK (Beam, calc_direction, 1); SCM @@ -135,7 +151,7 @@ Beam::calc_direction (SCM smob) Direction dir = CENTER; - int count = visible_stem_count (me); + int count = normal_stem_count (me); if (count < 2) { extract_grob_set (me, "stems", stems); @@ -148,7 +164,7 @@ Beam::calc_direction (SCM smob) } else { - Grob *stem = first_visible_stem (me); + Grob *stem = first_normal_stem (me); /* ugh: stems[0] case happens for chord tremolo. @@ -217,7 +233,7 @@ position_with_maximal_common_beams (SCM left_beaming, SCM right_beaming, return best_start; } -MAKE_SCHEME_CALLBACK(Beam, calc_beaming, 1) +MAKE_SCHEME_CALLBACK (Beam, calc_beaming, 1) SCM Beam::calc_beaming (SCM smob) { @@ -265,6 +281,9 @@ Beam::calc_beaming (SCM smob) } else { + /* + FIXME: what's this for? + */ SCM s = scm_cdr (this_beaming); for (; scm_is_pair (s); s = scm_cdr (s)) { @@ -296,6 +315,10 @@ typedef map > Position_stem_segments_map; vector Beam::get_beam_segments (Grob *me_grob, Grob **common) { + /* ugh, this has a side-effect that we need to ensure that + Stem #'beaming is correct */ + (void) me_grob->get_property ("beaming"); + Spanner *me = dynamic_cast (me_grob); extract_grob_set (me, "stems", stems); @@ -368,7 +391,7 @@ Beam::get_beam_segments (Grob *me_grob, Grob **common) i != stem_segments.end (); i++) { vector segs = (*i).second; - vector_sort (segs, default_compare); + vector_sort (segs, less ()); Beam_segment current; @@ -381,10 +404,14 @@ Beam::get_beam_segments (Grob *me_grob, Grob **common) Direction event_dir = LEFT; do { - Drul_array on_bound (j == 0 && event_dir==LEFT, - j == segs.size() - 1 && event_dir==RIGHT); - Drul_array inside (j > 0, j < segs.size()-1); - bool event = on_bound[event_dir] + bool on_bound = (event_dir == LEFT) ? j == 0 : + j == segs.size () - 1; + + bool inside_stem = (event_dir == LEFT) + ? segs[j].stem_index_ > 0 + : segs[j].stem_index_ + 1 < stems.size () ; + + bool event = on_bound || abs (segs[j].rank_ - segs[j+event_dir].rank_) > 1 || (abs (vertical_count) >= segs[j].max_connect_ || abs (vertical_count) >= segs[j + event_dir].max_connect_); @@ -396,11 +423,12 @@ Beam::get_beam_segments (Grob *me_grob, Grob **common) current.horizontal_[event_dir] = segs[j].stem_x_; if (segs[j].dir_ == event_dir) { - if (on_bound[event_dir] + if (on_bound && me->get_bound (event_dir)->break_status_dir ()) { current.horizontal_[event_dir] - = (me->get_bound (event_dir)->extent (commonx, X_AXIS)[RIGHT] + = (robust_relative_extent (me->get_bound (event_dir), + commonx, X_AXIS)[RIGHT] + event_dir * break_overshoot[event_dir]); } else @@ -409,12 +437,17 @@ Beam::get_beam_segments (Grob *me_grob, Grob **common) Stem::duration_log (segs[j].stem_) == 1 ? 1.98 : 1.32; // URG. - - if (inside[event_dir]) - notehead_width = min (notehead_width, - fabs (segs[j+ event_dir].stem_x_ - - segs[j].stem_x_)/2); - + + + if (inside_stem) + { + Grob *neighbor_stem = stems[segs[j].stem_index_ + event_dir]; + Real neighbor_stem_x + = neighbor_stem->relative_coordinate (commonx, X_AXIS); + + notehead_width = min (notehead_width, + fabs (neighbor_stem_x - segs[j].stem_x_)/2); + } current.horizontal_[event_dir] += event_dir * notehead_width; } } @@ -422,13 +455,32 @@ Beam::get_beam_segments (Grob *me_grob, Grob **common) { current.horizontal_[event_dir] += event_dir * segs[j].width_/2; if (segs[j].gapped_) - current.horizontal_[event_dir] -= event_dir * gap_length; + { + current.horizontal_[event_dir] -= event_dir * gap_length; + + if (Stem::is_invisible (segs[j].stem_)) + { + /* + Need to do this in case of whole notes. We don't want the + heads to collide with the beams. + */ + extract_grob_set (segs[j].stem_, "note-heads", heads); + + for (vsize k = 0; k < heads.size (); k ++) + current.horizontal_[event_dir] + = event_dir * min (event_dir * current.horizontal_[event_dir], + - gap_length/2 + + event_dir + * heads[k]->extent (commonx, + X_AXIS)[-event_dir]); + } + } } if (event_dir == RIGHT) { segments.push_back (current); - current = Beam_segment(); + current = Beam_segment (); } } while (flip (&event_dir) != LEFT); @@ -439,7 +491,7 @@ Beam::get_beam_segments (Grob *me_grob, Grob **common) return segments; } -MAKE_SCHEME_CALLBACK(Beam, print, 1); +MAKE_SCHEME_CALLBACK (Beam, print, 1); SCM Beam::print (SCM grob) { @@ -448,10 +500,10 @@ Beam::print (SCM grob) vector segments = get_beam_segments (me, &commonx); Interval span; - if (visible_stem_count (me)) + if (normal_stem_count (me)) { - span[LEFT] = first_visible_stem (me)->relative_coordinate (commonx, X_AXIS); - span[RIGHT] = last_visible_stem (me)->relative_coordinate (commonx, X_AXIS); + span[LEFT] = first_normal_stem (me)->relative_coordinate (commonx, X_AXIS); + span[RIGHT] = last_normal_stem (me)->relative_coordinate (commonx, X_AXIS); } else { @@ -523,7 +575,7 @@ Beam::print (SCM grob) (me->layout ()->self_scm (), properties, quant_score)); if (!score.is_empty ()) - the_beam.add_at_edge (Y_AXIS, stem_dir, score, 1.0, 0); + the_beam.add_at_edge (Y_AXIS, stem_dir, score, 1.0); } #endif @@ -557,7 +609,7 @@ Beam::get_default_dir (Grob *me) { Grob *s = stems[i]; Direction stem_dir = CENTER; - SCM stem_dir_scm = s->get_property_data (ly_symbol2scm ("direction")); + SCM stem_dir_scm = s->get_property_data ("direction"); if (is_direction (stem_dir_scm)) { stem_dir = to_dir (stem_dir_scm); @@ -613,7 +665,7 @@ Beam::set_stem_directions (Grob *me, Direction d) { Grob *s = stems[i]; - SCM forcedir = s->get_property_data (ly_symbol2scm ("direction")); + SCM forcedir = s->get_property_data ("direction"); if (!to_dir (forcedir)) set_grob_direction (s, d); } @@ -642,7 +694,7 @@ Beam::consider_auto_knees (Grob *me) gaps.set_full (); - extract_grob_set (me, "stems", stems); + extract_grob_set (me, "normal-stems", stems); Grob *common = common_refpoint_of_array (stems, me, Y_AXIS); Real staff_space = Staff_symbol_referencer::staff_space (me); @@ -651,8 +703,6 @@ Beam::consider_auto_knees (Grob *me) for (vsize i = 0; i < stems.size (); i++) { Grob *stem = stems[i]; - if (Stem::is_invisible (stem)) - continue; Interval head_extents = Stem::head_positions (stem); if (!head_extents.is_empty ()) @@ -666,9 +716,9 @@ Beam::consider_auto_knees (Grob *me) sets stem directions, a constant shift does not have an influence. */ - head_extents += stem->relative_coordinate (common, Y_AXIS); + head_extents += stem->pure_relative_y_coordinate (common, 0, INT_MAX); - if (to_dir (stem->get_property_data (ly_symbol2scm ("direction")))) + if (to_dir (stem->get_property_data ("direction"))) { Direction stemdir = to_dir (stem->get_property ("direction")); head_extents[-stemdir] = -stemdir * infinity_f; @@ -712,9 +762,6 @@ Beam::consider_auto_knees (Grob *me) for (vsize i = 0; i < stems.size (); i++) { Grob *stem = stems[i]; - if (Stem::is_invisible (stem)) - continue; - Interval head_extents = head_extents_array[j++]; Direction d = (head_extents.center () < max_gap.center ()) @@ -764,7 +811,7 @@ set_minimum_dy (Grob *me, Real *dy) -MAKE_SCHEME_CALLBACK(Beam, calc_stem_shorten, 1) +MAKE_SCHEME_CALLBACK (Beam, calc_stem_shorten, 1) SCM Beam::calc_stem_shorten (SCM smob) { @@ -777,7 +824,7 @@ Beam::calc_stem_shorten (SCM smob) return scm_from_int (0); Real forced_fraction = 1.0 * forced_stem_count (me) - / visible_stem_count (me); + / normal_stem_count (me); int beam_count = get_beam_count (me); @@ -813,27 +860,27 @@ Beam::calc_least_squares_positions (SCM smob, SCM posns) Grob *me = unsmob_grob (smob); - int count = visible_stem_count (me); + int count = normal_stem_count (me); Interval pos (0,0); if (count < 1) return ly_interval2scm (pos); vector x_posns; - extract_grob_set (me, "stems", stems); + extract_grob_set (me, "normal-stems", stems); Grob *commonx = common_refpoint_of_array (stems, me, X_AXIS); Grob *commony = common_refpoint_of_array (stems, me, Y_AXIS); Real my_y = me->relative_coordinate (commony, Y_AXIS); - Grob *fvs = first_visible_stem (me); - Grob *lvs = last_visible_stem (me); + Grob *fvs = first_normal_stem (me); + Grob *lvs = last_normal_stem (me); Interval ideal (Stem::get_stem_info (fvs).ideal_y_ + fvs->relative_coordinate (commony, Y_AXIS) - my_y, Stem::get_stem_info (lvs).ideal_y_ + lvs->relative_coordinate (commony, Y_AXIS) - my_y); - Real x0 = first_visible_stem (me)->relative_coordinate (commonx, X_AXIS); + Real x0 = first_normal_stem (me)->relative_coordinate (commonx, X_AXIS); for (vsize i = 0; i < stems.size (); i++) { Grob *s = stems[i]; @@ -841,7 +888,7 @@ Beam::calc_least_squares_positions (SCM smob, SCM posns) Real x = s->relative_coordinate (commonx, X_AXIS) - x0; x_posns.push_back (x); } - Real dx = last_visible_stem (me)->relative_coordinate (commonx, X_AXIS) - x0; + Real dx = last_normal_stem (me)->relative_coordinate (commonx, X_AXIS) - x0; Real y = 0; Real slope = 0; @@ -849,8 +896,8 @@ Beam::calc_least_squares_positions (SCM smob, SCM posns) Real ldy = 0.0; if (!ideal.delta ()) { - Interval chord (Stem::chord_start_y (first_visible_stem (me)), - Stem::chord_start_y (last_visible_stem (me))); + Interval chord (Stem::chord_start_y (stems[0]), + Stem::chord_start_y (stems.back ())); /* Simple beams (2 stems) on middle line should be allowed to be slightly sloped. @@ -882,8 +929,6 @@ Beam::calc_least_squares_positions (SCM smob, SCM posns) for (vsize i = 0; i < stems.size (); i++) { Grob *s = stems[i]; - if (Stem::is_invisible (s)) - continue; ideals.push_back (Offset (x_posns[i], Stem::get_stem_info (s).ideal_y_ + s->relative_coordinate (commony, Y_AXIS) @@ -929,7 +974,7 @@ Beam::shift_region_to_valid (SCM grob, SCM posns) Grob *commonx = common_refpoint_of_array (stems, me, X_AXIS); Grob *commony = common_refpoint_of_array (stems, me, Y_AXIS); - Grob *fvs = first_visible_stem (me); + Grob *fvs = first_normal_stem (me); if (!fvs) return posns; @@ -943,14 +988,13 @@ Beam::shift_region_to_valid (SCM grob, SCM posns) x_posns.push_back (x); } - Grob *lvs = last_visible_stem (me); + Grob *lvs = last_normal_stem (me); if (!lvs) return posns; Real dx = lvs->relative_coordinate (commonx, X_AXIS) - x0; Drul_array pos = ly_scm2interval (posns); - scale_drul (&pos, Staff_symbol_referencer::staff_space (me)); @@ -1020,7 +1064,7 @@ Beam::slope_damping (SCM smob, SCM posns) Grob *me = unsmob_grob (smob); Drul_array pos = ly_scm2interval (posns); - if (visible_stem_count (me) <= 1) + if (normal_stem_count (me) <= 1) return posns; @@ -1040,13 +1084,13 @@ Beam::slope_damping (SCM smob, SCM posns) Real dy = pos[RIGHT] - pos[LEFT]; - Grob *fvs = first_visible_stem (me); - Grob *lvs = last_visible_stem (me); + Grob *fvs = first_normal_stem (me); + Grob *lvs = last_normal_stem (me); Grob *commonx = fvs->common_refpoint (lvs, X_AXIS); - Real dx = last_visible_stem (me)->relative_coordinate (commonx, X_AXIS) - - first_visible_stem (me)->relative_coordinate (commonx, X_AXIS); + Real dx = last_normal_stem (me)->relative_coordinate (commonx, X_AXIS) + - first_normal_stem (me)->relative_coordinate (commonx, X_AXIS); Real slope = dy && dx ? dy / dx : 0; @@ -1128,7 +1172,7 @@ Beam::calc_stem_y (Grob *me, Grob *stem, Grob **common, Hmm. At this time, beam position and slope are determined. Maybe, stem directions and length should set to relative to the chord's position of the beam. */ -MAKE_SCHEME_CALLBACK(Beam, set_stem_lengths, 1); +MAKE_SCHEME_CALLBACK (Beam, set_stem_lengths, 1); SCM Beam::set_stem_lengths (SCM smob) { @@ -1160,8 +1204,8 @@ Beam::set_stem_lengths (SCM smob) thick = get_thickness (me); } - Grob *fvs = first_visible_stem (me); - Grob *lvs = last_visible_stem (me); + Grob *fvs = first_normal_stem (me); + Grob *lvs = last_normal_stem (me); Real xl = fvs ? fvs->relative_coordinate (common[X_AXIS], X_AXIS) : 0.0; Real xr = lvs ? lvs->relative_coordinate (common[X_AXIS], X_AXIS) : 0.0; @@ -1169,8 +1213,6 @@ Beam::set_stem_lengths (SCM smob) for (vsize i = 0; i < stems.size (); i++) { Grob *s = stems[i]; - if (Stem::is_invisible (s)) - continue; bool french = to_boolean (s->get_property ("french-beaming")); Real stem_y = calc_stem_y (me, s, common, @@ -1181,9 +1223,14 @@ Beam::set_stem_lengths (SCM smob) Make the stems go up to the end of the beam. This doesn't matter for normal beams, but for tremolo beams it looks silly otherwise. */ - if (gap) + if (gap + && !Stem::is_invisible (s)) stem_y += thick * 0.5 * get_grob_direction (s); + /* + Do set_stemend for invisible stems too, so tuplet brackets + have a reference point for sloping + */ Stem::set_stemend (s, 2 * stem_y / staff_space); } @@ -1210,7 +1257,7 @@ Beam::set_beaming (Grob *me, Beaming_pattern const *beaming) { int count = beaming->beamlet_count (i, d); if (i > 0 - && i < stems.size () -1 + && i + 1 < stems.size () && Stem::is_invisible (stem)) count = min (count, beaming->beamlet_count (i,-d)); @@ -1230,16 +1277,13 @@ Beam::set_beaming (Grob *me, Beaming_pattern const *beaming) int Beam::forced_stem_count (Grob *me) { - extract_grob_set (me, "stems", stems); + extract_grob_set (me, "normal-stems", stems); int f = 0; for (vsize i = 0; i < stems.size (); i++) { Grob *s = stems[i]; - if (Stem::is_invisible (s)) - continue; - /* I can imagine counting those boundaries as a half forced stem, but let's count them full for now. */ Direction defdir = to_dir (s->get_property ("default-direction")); @@ -1253,42 +1297,24 @@ Beam::forced_stem_count (Grob *me) } int -Beam::visible_stem_count (Grob *me) +Beam::normal_stem_count (Grob *me) { - extract_grob_set (me, "stems", stems); - int c = 0; - for (vsize i = stems.size (); i--;) - { - if (!Stem::is_invisible (stems[i])) - c++; - } - return c; + extract_grob_set (me, "normal-stems", stems); + return stems.size (); } Grob * -Beam::first_visible_stem (Grob *me) +Beam::first_normal_stem (Grob *me) { - extract_grob_set (me, "stems", stems); - - for (vsize i = 0; i < stems.size (); i++) - { - if (!Stem::is_invisible (stems[i])) - return stems[i]; - } - return 0; + extract_grob_set (me, "normal-stems", stems); + return stems.size () ? stems[0] : 0; } Grob * -Beam::last_visible_stem (Grob *me) +Beam::last_normal_stem (Grob *me) { - extract_grob_set (me, "stems", stems); - - for (vsize i = stems.size (); i--;) - { - if (!Stem::is_invisible (stems[i])) - return stems[i]; - } - return 0; + extract_grob_set (me, "normal-stems", stems); + return stems.size () ? stems.back () : 0; } /* @@ -1301,7 +1327,7 @@ Beam::last_visible_stem (Grob *me) rest -> stem -> beam -> interpolate_y_position () */ -MAKE_SCHEME_CALLBACK (Beam, rest_collision_callback, 2); +MAKE_SCHEME_CALLBACK_WITH_OPTARGS (Beam, rest_collision_callback, 2, 1, ""); SCM Beam::rest_collision_callback (SCM smob, SCM prev_offset) { @@ -1318,15 +1344,11 @@ Beam::rest_collision_callback (SCM smob, SCM prev_offset) Grob *beam = unsmob_grob (stem->get_object ("beam")); if (!beam || !Beam::has_interface (beam) - || !Beam::visible_stem_count (beam)) + || !Beam::normal_stem_count (beam)) return scm_from_double (0.0); - Drul_array pos (0, 0); - SCM s = beam->get_property ("positions"); - if (scm_is_pair (s) && scm_is_number (scm_car (s))) - pos = ly_scm2interval (s); - else - programming_error ("positions property should always be pair of numbers."); + Drul_array pos (robust_scm2drul (beam->get_property ("positions"), + Drul_array (0,0))); Real staff_space = Staff_symbol_referencer::staff_space (rest); @@ -1334,8 +1356,8 @@ Beam::rest_collision_callback (SCM smob, SCM prev_offset) Real dy = pos[RIGHT] - pos[LEFT]; - Drul_array visible_stems (first_visible_stem (beam), - last_visible_stem (beam)); + Drul_array visible_stems (first_normal_stem (beam), + last_normal_stem (beam)); extract_grob_set (beam, "stems", stems); Grob *common = common_refpoint_of_array (stems, beam, X_AXIS); @@ -1362,6 +1384,11 @@ Beam::rest_collision_callback (SCM smob, SCM prev_offset) Real beam_y = stem_y - d * height_of_my_beams; Grob *common_y = rest->common_refpoint (beam, Y_AXIS); + + /* + TODO: this is dubious, because this call needs the info we're + computing right now. + */ Interval rest_extent = rest->extent (common_y, Y_AXIS); rest_extent.translate (offset); @@ -1370,7 +1397,7 @@ Beam::rest_collision_callback (SCM smob, SCM prev_offset) = staff_space * (robust_scm2double (stem->get_property ("stemlet-length"), 0.0) + robust_scm2double (rest->get_property ("minimum-distance"), 0.0)); - Real shift = d * min (((beam_y - d * minimum_distance) - rest_dim) * d, 0.0); + 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; @@ -1385,7 +1412,7 @@ Beam::rest_collision_callback (SCM smob, SCM prev_offset) < rad) shift = ceil (fabs (shift)) * sign (shift); - return scm_from_double (staff_space * shift); + return scm_from_double (offset + staff_space * shift); } bool @@ -1414,6 +1441,24 @@ Beam::is_knee (Grob *me) return knee; } +bool +Beam::is_cross_staff (Grob *me) +{ + extract_grob_set (me, "stems", stems); + Grob *staff_symbol = Staff_symbol_referencer::get_staff_symbol (me); + for (vsize i = 0; i < stems.size (); i++) + if (Staff_symbol_referencer::get_staff_symbol (stems[i]) != staff_symbol) + return true; + return false; +} + +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))); +} + int Beam::get_direction_beam_count (Grob *me, Direction d) { @@ -1433,7 +1478,6 @@ Beam::get_direction_beam_count (Grob *me, Direction d) } ADD_INTERFACE (Beam, - "beam-interface", "A beam. \n\n" "The @code{thickness} property is the weight of beams, " @@ -1461,6 +1505,7 @@ ADD_INTERFACE (Beam, "length-fraction " "least-squares-dy " "neutral-direction " + "normal-stems " "positions " "quant-score " "quantized-positions "