X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fbeam.cc;h=77953070c91192eb47af325d7ad013c44530c4c1;hb=804385793dcad0400e6b7ccfe006fece27e5feac;hp=0c5246c501a2f453d44e1dfe99ca3a807a8ada11;hpb=b1bf1348924a5526a96bbc80f60a0d128b35522c;p=lilypond.git diff --git a/lily/beam.cc b/lily/beam.cc index 0c5246c501..77953070c9 100644 --- a/lily/beam.cc +++ b/lily/beam.cc @@ -26,7 +26,7 @@ #include "beam.hh" -#include "beaming.hh" +#include "beaming-pattern.hh" #include "directional-element-interface.hh" #include "main.hh" #include "international.hh" @@ -52,6 +52,7 @@ Beam_stem_segment::Beam_stem_segment () { + max_connect_ = 1000; // infinity stem_ = 0; width_ = 0.0; stem_x_ = 0.0; @@ -128,29 +129,21 @@ Beam::calc_direction (SCM smob) /* Beams with less than 2 two stems don't make much sense, but could happen when you do - [r8 c8 r8]. + r8[ c8 r8] - For a beam that only has one stem, we try to do some disappearance magic: - we revert the flag, and move on to The Eternal Engraving Fields. */ + */ - Direction d = CENTER; + Direction dir = CENTER; int count = visible_stem_count (me); if (count < 2) { extract_grob_set (me, "stems", stems); - if (stems.size () == 1) + if (stems.size () == 0) { - me->warning (_ ("removing beam with less than two stems")); - - stems[0]->set_object ("beam", SCM_EOL); + me->warning (_ ("removing beam with no stems")); me->suicide (); - return SCM_UNSPECIFIED; - } - else if (stems.size () == 0) - { - me->suicide (); return SCM_UNSPECIFIED; } else @@ -160,24 +153,24 @@ Beam::calc_direction (SCM smob) /* ugh: stems[0] case happens for chord tremolo. */ - d = to_dir ((stem ? stem : stems[0])->get_property ("default-direction")); + dir = to_dir ((stem ? stem : stems[0])->get_property ("default-direction")); } } if (count >= 1) { - if (!d) - d = get_default_dir (me); + if (!dir) + dir = get_default_dir (me); consider_auto_knees (me); } - if (d) + if (dir) { - set_stem_directions (me, d); + set_stem_directions (me, dir); } - return scm_from_int (d); + return scm_from_int (dir); } @@ -303,6 +296,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 ("quantized-positions"); + Spanner *me = dynamic_cast (me_grob); extract_grob_set (me, "stems", stems); @@ -313,9 +310,14 @@ Beam::get_beam_segments (Grob *me_grob, Grob **common) *common = commonx; + int gap_count = robust_scm2int (me->get_property ("gap-count"), 0); + Real gap_length = robust_scm2double (me->get_property ("gap"), 0.0); + Position_stem_segments_map stem_segments; Real lt = me->layout ()->get_dimension (ly_symbol2scm ("line-thickness")); + Slice ranks; + for (vsize i = 0; i < stems.size (); i++) { Grob *stem = stems[i]; @@ -330,7 +332,18 @@ Beam::get_beam_segments (Grob *me_grob, Grob **common) { if (!scm_is_integer (scm_car (s))) continue; - + + int beam_rank = scm_to_int (scm_car (s)); + ranks.add_point (beam_rank); + } + + for (SCM s = index_get_cell (beaming, d); + scm_is_pair (s); s = scm_cdr (s)) + { + if (!scm_is_integer (scm_car (s))) + continue; + + int beam_rank = scm_to_int (scm_car (s)); Beam_stem_segment seg; seg.stem_ = stem; seg.stem_x_ = stem_x; @@ -338,7 +351,13 @@ Beam::get_beam_segments (Grob *me_grob, Grob **common) seg.width_ = stem_width; seg.stem_index_ = i; seg.dir_ = d; - stem_segments[scm_to_int (scm_car (s))].push_back (seg); + seg.max_connect_ = robust_scm2int (stem->get_property ("max-beam-connect"), 1000); + + Direction stem_dir = get_grob_direction (stem); + + seg.gapped_ + = (stem_dir * beam_rank < (stem_dir * ranks[-stem_dir] + gap_count)); + stem_segments[beam_rank].push_back (seg); } } while (flip (&d) != LEFT); @@ -353,10 +372,11 @@ 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; - current.vertical_count_ = (*i).first; + + int vertical_count = (*i).first; for (vsize j = 0; j < segs.size (); j++) { /* @@ -365,45 +385,60 @@ 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] - || abs (segs[j].rank_ - segs[j+event_dir].rank_) > 1; + 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_ < stems.size () - 1; + + 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_); if (!event) continue; - current.vertical_count_ = (*i).first; + current.vertical_count_ = vertical_count; current.horizontal_[event_dir] = segs[j].stem_x_; if (segs[j].dir_ == event_dir) { - if (on_bound[event_dir] && me->get_bound (event_dir)->break_status_dir ()) + if (on_bound + && me->get_bound (event_dir)->break_status_dir ()) { - current.horizontal_[event_dir] += event_dir * break_overshoot[event_dir]; + current.horizontal_[event_dir] + = (me->get_bound (event_dir)->extent (commonx, X_AXIS)[RIGHT] + + event_dir * break_overshoot[event_dir]); } else { Real notehead_width = 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); - + ? 1.98 + : 1.32; // URG. + + + 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; } } else { current.horizontal_[event_dir] += event_dir * segs[j].width_/2; + if (segs[j].gapped_) + current.horizontal_[event_dir] -= event_dir * gap_length; } if (event_dir == RIGHT) { - current.vertical_count_ = (*i).first; segments.push_back (current); current = Beam_segment(); } @@ -424,23 +459,23 @@ Beam::print (SCM grob) Grob *commonx = 0; vector segments = get_beam_segments (me, &commonx); - Real x0, dx; + Interval span; if (visible_stem_count (me)) { - x0 = first_visible_stem (me)->relative_coordinate (commonx, X_AXIS); - dx = last_visible_stem (me)->relative_coordinate (commonx, X_AXIS) - x0; + span[LEFT] = first_visible_stem (me)->relative_coordinate (commonx, X_AXIS); + span[RIGHT] = last_visible_stem (me)->relative_coordinate (commonx, X_AXIS); } else { extract_grob_set (me, "stems", stems); - x0 = stems[0]->relative_coordinate (commonx, X_AXIS); - dx = stems.back ()->relative_coordinate (commonx, X_AXIS) - x0; + span[LEFT] = stems[0]->relative_coordinate (commonx, X_AXIS); + span[RIGHT] = stems.back ()->relative_coordinate (commonx, X_AXIS); } Real blot = me->layout ()->get_dimension (ly_symbol2scm ("blot-diameter")); SCM posns = me->get_property ("quantized-positions"); - Drul_array pos; + Interval pos; if (!is_number_pair (posns)) { programming_error ("no beam positions?"); @@ -452,19 +487,29 @@ Beam::print (SCM grob) scale_drul (&pos, Staff_symbol_referencer::staff_space (me)); Real dy = pos[RIGHT] - pos[LEFT]; - Real slope = (dy && dx) ? dy / dx : 0; + Real slope = (dy && span.length ()) ? dy / span.length () : 0; Real thick = get_thickness (me); Real beam_dy = get_beam_translation (me); - + Direction feather_dir = to_dir (me->get_property ("grow-direction")); + Stencil the_beam; for (vsize i = 0; i < segments.size (); i ++) { - Stencil b = Lookup::beam (slope, segments[i].horizontal_.length (), thick, blot); + Real local_slope = slope; + if (feather_dir) + { + local_slope += feather_dir * segments[i].vertical_count_ * beam_dy / span.length (); + } + + Stencil b = Lookup::beam (local_slope, segments[i].horizontal_.length (), thick, blot); b.translate_axis (segments[i].horizontal_[LEFT], X_AXIS); - b.translate_axis (slope * (segments[i].horizontal_[LEFT] - x0) + + b.translate_axis (local_slope + * (segments[i].horizontal_[LEFT] - span.linear_combination (feather_dir)) + + pos.linear_combination (feather_dir) + beam_dy * segments[i].vertical_count_, Y_AXIS); the_beam.add_stencil (b); } @@ -494,7 +539,6 @@ Beam::print (SCM grob) } #endif - the_beam.translate_axis (pos[LEFT], Y_AXIS); the_beam.translate_axis (-me->relative_coordinate (commonx, X_AXIS), X_AXIS); return the_beam.smobbed_copy (); } @@ -525,7 +569,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); @@ -581,7 +625,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); } @@ -636,7 +680,7 @@ Beam::consider_auto_knees (Grob *me) */ head_extents += stem->relative_coordinate (common, Y_AXIS); - 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; @@ -785,7 +829,7 @@ Beam::calc_least_squares_positions (SCM smob, SCM posns) Interval pos (0,0); if (count < 1) return ly_interval2scm (pos); - + vector x_posns; extract_grob_set (me, "stems", stems); Grob *commonx = common_refpoint_of_array (stems, me, X_AXIS); @@ -797,7 +841,7 @@ Beam::calc_least_squares_positions (SCM smob, SCM posns) Grob *lvs = last_visible_stem (me); Interval ideal (Stem::get_stem_info (fvs).ideal_y_ - + fvs->relative_coordinate (commony, Y_AXIS) -my_y, + + fvs->relative_coordinate (commony, Y_AXIS) - my_y, Stem::get_stem_info (lvs).ideal_y_ + lvs->relative_coordinate (commony, Y_AXIS) - my_y); @@ -1055,13 +1099,13 @@ where_are_the_whole_beams (SCM beaming) /* Return the Y position of the stem-end, given the Y-left, Y-right in POS for stem S. This Y position is relative to S. */ Real -Beam::calc_stem_y (Grob *me, Grob *s, Grob ** common, +Beam::calc_stem_y (Grob *me, Grob *stem, Grob **common, Real xl, Real xr, Drul_array pos, bool french) { Real beam_translation = get_beam_translation (me); - Real r = s->relative_coordinate (common[X_AXIS], X_AXIS) - xl; + Real r = stem->relative_coordinate (common[X_AXIS], X_AXIS) - xl; Real dy = pos[RIGHT] - pos[LEFT]; Real dx = xr - xl; Real stem_y_beam0 = (dy && dx @@ -1069,8 +1113,8 @@ Beam::calc_stem_y (Grob *me, Grob *s, Grob ** common, * dy : 0) + pos[LEFT]; - Direction my_dir = get_grob_direction (s); - SCM beaming = s->get_property ("beaming"); + Direction my_dir = get_grob_direction (stem); + SCM beaming = stem->get_property ("beaming"); Real stem_y = stem_y_beam0; if (french) @@ -1081,13 +1125,13 @@ Beam::calc_stem_y (Grob *me, Grob *s, Grob ** common, } else { - Slice bm = Stem::beam_multiplicity (s); + Slice bm = Stem::beam_multiplicity (stem); if (!bm.is_empty ()) stem_y += bm[my_dir] * beam_translation; } Real id = me->relative_coordinate (common[Y_AXIS], Y_AXIS) - - s->relative_coordinate (common[Y_AXIS], Y_AXIS); + - stem->relative_coordinate (common[Y_AXIS], Y_AXIS); return stem_y + id; } @@ -1102,8 +1146,9 @@ Beam::set_stem_lengths (SCM smob) { Grob *me = unsmob_grob (smob); - /* trigger callback. */ + /* trigger callbacks. */ (void) me->get_property ("direction"); + (void) me->get_property ("beaming"); SCM posns = me->get_property ("positions"); @@ -1121,8 +1166,7 @@ Beam::set_stem_lengths (SCM smob) bool gap = false; Real thick = 0.0; - if (scm_is_number (me->get_property ("gap-count")) - && scm_to_int (me->get_property ("gap-count"))) + if (robust_scm2int (me->get_property ("gap-count"), 0)) { gap = true; thick = get_thickness (me); @@ -1137,8 +1181,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, @@ -1149,9 +1191,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); } @@ -1159,7 +1206,7 @@ Beam::set_stem_lengths (SCM smob) } void -Beam::set_beaming (Grob *me, Beaming_info_list const *beaming) +Beam::set_beaming (Grob *me, Beaming_pattern const *beaming) { extract_grob_set (me, "stems", stems); @@ -1176,13 +1223,19 @@ Beam::set_beaming (Grob *me, Beaming_info_list const *beaming) if (beaming_prop == SCM_EOL || index_get_cell (beaming_prop, d) == SCM_EOL) { - int b = beaming->infos_.at (i).beams_i_drul_[d]; + int count = beaming->beamlet_count (i, d); if (i > 0 && i < stems.size () -1 && Stem::is_invisible (stem)) - b = min (b, beaming->infos_.at (i).beams_i_drul_[-d]); + count = min (count, beaming->beamlet_count (i,-d)); + + if ( ((i == 0 && d == LEFT) + || (i == stems.size ()-1 && d == RIGHT)) + && stems.size () > 1 + && to_boolean (me->get_property ("clip-edges"))) + count = 0; - Stem::set_beaming (stem, b, d); + Stem::set_beaming (stem, count, d); } } while (flip (&d) != LEFT); @@ -1263,7 +1316,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) { @@ -1395,7 +1448,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, " @@ -1410,13 +1462,14 @@ ADD_INTERFACE (Beam, "beamed-stem-shorten " "beaming " "break-overshoot " - "chord-tremolo " + "clip-edges " "concaveness " "damping " "details " "direction " "gap " "gap-count " + "grow-direction " "inspect-quants " "knee " "length-fraction "