diff options
author | Carl Sorensen <c_sorensen@byu.edu> | 2011-08-20 16:41:03 -0600 |
---|---|---|
committer | David Kastrup <dak@gnu.org> | 2011-11-24 11:33:26 +0100 |
commit | 44155056614ee1ff6b3bf4f286bdb386147c21a2 (patch) | |
tree | 40edd58396969bb72e569403b8dc792b164c185a | |
parent | bac64a7481cde0252c0a7eafc14a25e3b9bc3892 (diff) |
Fix beamlet pointing wrong way in tuplets (issue 11).
Add data structure to capture the tuplet structure.
Make beaming reflect subdivisions.
Eliminate rule to force minimum beamlets by combining all beams,
and replace it with rule to make beamlets point toward complete
beats (high rhythmic importance).
Add regression tests.
Adjust to handle beats properly for subdivision
Add regression test for beamlets pointing toward beats
-rw-r--r-- | input/regression/beam-multiplicity-over-rests.ly | 8 | ||||
-rw-r--r-- | input/regression/beamlet-point-toward-beat.ly | 14 | ||||
-rw-r--r-- | input/regression/beamlet-test.ly | 36 | ||||
-rw-r--r-- | lily/auto-beam-engraver.cc | 8 | ||||
-rw-r--r-- | lily/beam-engraver.cc | 8 | ||||
-rw-r--r-- | lily/beaming-pattern.cc | 178 | ||||
-rw-r--r-- | lily/include/beaming-pattern.hh | 7 |
7 files changed, 198 insertions, 61 deletions
diff --git a/input/regression/beam-multiplicity-over-rests.ly b/input/regression/beam-multiplicity-over-rests.ly index 5578931633..f16c8c6467 100644 --- a/input/regression/beam-multiplicity-over-rests.ly +++ b/input/regression/beam-multiplicity-over-rests.ly @@ -1,14 +1,14 @@ -\version "2.14.0" +\version "2.15.17" \header { - texidoc = "When a beam goes over a rest, there should not be any -beamlets pointing towards the rest unless absolutely necessary." + texidoc = "When a beam goes over a rest, beamlets should be as necessary + to show the beat structure." } \relative c' { c8[ r16 c32 c32] c32[ r16 c32 c8] - c32[ r16 c64 c8 c64] + c32[ r16 c64 c64 ~ c16.. c64] c32[ c32 r16 c8] c16[ r32 c32 r16 c16] c16[ r16 c32 r32 c16] diff --git a/input/regression/beamlet-point-toward-beat.ly b/input/regression/beamlet-point-toward-beat.ly new file mode 100644 index 0000000000..b1a761fdbb --- /dev/null +++ b/input/regression/beamlet-point-toward-beat.ly @@ -0,0 +1,14 @@ +\version "2.15.20" + +\header { + texidoc = " +Beamlets should point in the direction of the beat to which they +belong. +" +} + + +\relative c' { +b16. b32 b32 b16. +b16.[ b32 b b b b16.] +} diff --git a/input/regression/beamlet-test.ly b/input/regression/beamlet-test.ly new file mode 100644 index 0000000000..dc8d5f037e --- /dev/null +++ b/input/regression/beamlet-test.ly @@ -0,0 +1,36 @@ +\version "2.15.20" + +\header { + texidoc = " +Beamlets should point away from complete beat units and toward off-beat or +broken beat units. This should work in tuplets as well as in ordinary time. +" +} + +\relative c'' { + \times 2/3 { + c8. c16 c8 + } + \times 2/3 { + c8 c16 c8. + } + \times 4/5 { + c8[ c8. c16 c8 c8] + } + \times 4/5 { + c8[ c8 c16 c8. c8] + } + \times 4/5 { + c8 c16 c8. c8 c8 + } + \times 4/5 { + c8 c8 c8. c16 c8 + } + c8.[ c16 c8 c8] + c8[ c16 c8. c8] + c8[ c8. c16 c8] + c8.[ c16 c8. c16] + \times 4/5 { c8 [ c16 c8 c16 c8 c8 ] } + \times 4/5 { a8 a32 a8 a16. a8 a8 } +} + diff --git a/lily/auto-beam-engraver.cc b/lily/auto-beam-engraver.cc index 76a3023e10..b3cd6f4bab 100644 --- a/lily/auto-beam-engraver.cc +++ b/lily/auto-beam-engraver.cc @@ -404,7 +404,10 @@ Auto_beam_engraver::acknowledge_stem (Grob_info info) if (bool (beam_start_location_.grace_part_) != bool (now.grace_part_)) return; - Moment dur = unsmob_duration (ev->get_property ("duration"))->get_length (); + Duration *stem_duration = unsmob_duration (ev->get_property ("duration")); + Moment dur = stem_duration->get_length (); + + //Moment dur = unsmob_duration (ev->get_property ("duration"))->get_length (); Moment measure_now = measure_position (context ()); bool recheck_needed = false; @@ -425,7 +428,8 @@ Auto_beam_engraver::acknowledge_stem (Grob_info info) grouping_->add_stem (now - beam_start_moment_ + beam_start_location_, durlog - 2, - Stem::is_invisible (stem)); + Stem::is_invisible (stem), + stem_duration->factor ()); stems_->push_back (stem); last_add_mom_ = now; extend_mom_ = max (extend_mom_, now) + get_event_length (ev, now); diff --git a/lily/beam-engraver.cc b/lily/beam-engraver.cc index 654a7f57d1..e28d156836 100644 --- a/lily/beam-engraver.cc +++ b/lily/beam-engraver.cc @@ -268,7 +268,10 @@ Beam_engraver::acknowledge_stem (Grob_info info) } last_stem_added_at_ = now; - int durlog = unsmob_duration (ev->get_property ("duration"))->duration_log (); + + Duration *stem_duration = unsmob_duration (ev->get_property ("duration")); + int durlog = stem_duration->duration_log (); + //int durlog = unsmob_duration (ev->get_property ("duration"))->duration_log (); if (durlog <= 2) { ev->origin ()->warning (_ ("stem does not fit in beam")); @@ -287,7 +290,8 @@ Beam_engraver::acknowledge_stem (Grob_info info) Moment stem_location = now - beam_start_mom_ + beam_start_location_; beam_info_->add_stem (stem_location, max (durlog - 2, 0), - Stem::is_invisible (stem)); + Stem::is_invisible (stem), + stem_duration->factor ()); Beam::add_stem (beam_, stem); } diff --git a/lily/beaming-pattern.cc b/lily/beaming-pattern.cc index ada6770a5c..916ec145af 100644 --- a/lily/beaming-pattern.cc +++ b/lily/beaming-pattern.cc @@ -39,16 +39,18 @@ Beam_rhythmic_element::Beam_rhythmic_element () beam_count_drul_[LEFT] = 0; beam_count_drul_[RIGHT] = 0; invisible_ = false; + factor_ = Rational (1); } -Beam_rhythmic_element::Beam_rhythmic_element (Moment m, int i, bool inv) +Beam_rhythmic_element::Beam_rhythmic_element (Moment m, int i, bool inv, Rational factor) { start_moment_ = m; rhythmic_importance_ = 0; beam_count_drul_[LEFT] = i; beam_count_drul_[RIGHT] = i; invisible_ = inv; + factor_ = factor; } void @@ -98,15 +100,9 @@ Beaming_pattern::flag_direction (Beaming_options const &options, vsize i) const if (count <= left_count && count <= right_count) return CENTER; - // Try to avoid sticking-out flags as much as possible by pointing my flags - // at the neighbour with the most flags. - else if (right_count > left_count) - return RIGHT; - else if (left_count > right_count) - return LEFT; - // If all else fails, point the beamlet away from the important moment. - return (infos_[i].rhythmic_importance_ <= infos_[i + 1].rhythmic_importance_) ? RIGHT : LEFT; + return (infos_[i].rhythmic_importance_ <= infos_[i + 1].rhythmic_importance_) + ? RIGHT : LEFT; } void @@ -135,68 +131,141 @@ Beaming_pattern::beamify (Beaming_options const &options) find_rhythmic_importance (options); + vector <Direction> flag_directions; + // Get the initial flag directions + for (vsize i = 0; i < infos_.size (); i++) + flag_directions.push_back (flag_direction (options, i)); + + // Correct flag directions for subdivision for (vsize i = 1; i < infos_.size () - 1; i++) { - Direction non_flag_dir = other_dir (flag_direction (options, i)); - if (non_flag_dir) + if ((flag_directions[i] == CENTER) && (flag_directions[i - 1] == LEFT)) + flag_directions[i] = RIGHT; + if ((flag_directions[i] == CENTER) && (flag_directions[i + 1] == RIGHT)) + flag_directions[i] = LEFT; + } + + // Set the count on each side of the stem + // We need to run this code twice to make both the + // left and the right counts work properly + for (int i = 0; i < 2; i++) + for (vsize i = 1; i < infos_.size () - 1; i++) + { + Direction non_flag_dir = other_dir (flag_directions[i]); + if (non_flag_dir) + { + int importance = infos_[i + 1].rhythmic_importance_; + int count = (importance < 0 && options.subdivide_beams_) + ? 1 : min (min (infos_[i].count (non_flag_dir), + infos_[i + non_flag_dir].count (-non_flag_dir)), + infos_[i - non_flag_dir].count (non_flag_dir)); + + infos_[i].beam_count_drul_[non_flag_dir] = count; + } + } +} + +/* + Get the group start position, the next group starting position, and the + next beat starting position, given start_moment, base_moment, + grouping, and factor +*/ +void +find_location (SCM grouping, Moment base_moment, Moment start_moment, + Rational factor, Moment *group_pos, Moment *next_group_pos, + Moment *next_beat_pos) +{ + *group_pos = Moment (0); + *next_group_pos = Moment (0); + *next_beat_pos = base_moment; + + while (*next_beat_pos <= start_moment) + *next_beat_pos += base_moment; + + while (*next_group_pos < *next_beat_pos) + { + int count = 1; //default -- 1 base moments in a beam + if (scm_is_pair (grouping)) { - int importance = (non_flag_dir == LEFT) - ? infos_[i].rhythmic_importance_ : infos_[i + 1].rhythmic_importance_; - int count = (importance < 0 && options.subdivide_beams_) - ? 1 : min (infos_[i].count (non_flag_dir), - infos_[i + non_flag_dir].count (-non_flag_dir)); + count = scm_to_int (scm_car (grouping)); + grouping = scm_cdr (grouping); + } - infos_[i].beam_count_drul_[non_flag_dir] = count; + // If we have a tuplet, the count should be determined from + // the maximum tuplet size for beamed tuplets. + int tuplet_count = factor.num (); + if (tuplet_count > 1) + { + // We use 1/8 as the base moment for the tuplet because it's + // the largest beamed value. If the tuplet is shorter, it's + // OK, the code still works + int test_count = (tuplet_count * Moment (Rational (1, 8)) / base_moment).num (); + if (test_count > count) count = test_count; } + *group_pos = *next_group_pos; + *next_group_pos = *group_pos + count * base_moment; } } void Beaming_pattern::find_rhythmic_importance (Beaming_options const &options) { - Moment measure_pos (0); + Moment group_pos (0); // 0 is the start of the first group + Moment next_group_pos (0); + Moment next_beat_pos (options.base_moment_); + int tuplet_count = 1; + SCM grouping = options.grouping_; vsize i = 0; + // Find where we are in the beat structure of the measure + if (infos_.size ()) + find_location (grouping, options.base_moment_, infos_[i].start_moment_, + infos_[i].factor_, &group_pos, &next_group_pos, &next_beat_pos); + // Mark the importance of stems that start at a beat or a beat group. while (i < infos_.size ()) { - // If a beat grouping is not specified, default to 2 beats per group. - int count = 2; - if (scm_is_pair (grouping)) - { - count = scm_to_int (scm_car (grouping)); - grouping = scm_cdr (grouping); - } - + tuplet_count = infos_[i].factor_.den (); + if ((next_beat_pos > next_group_pos) + || (infos_[i].start_moment_ > next_beat_pos)) + // Find the new group ending point + find_location (grouping, options.base_moment_, infos_[i].start_moment_, + infos_[i].factor_, &group_pos, &next_group_pos, &next_beat_pos); // Mark the start of this beat group - if (infos_[i].start_moment_ == measure_pos) + if (infos_[i].start_moment_ == group_pos) infos_[i].rhythmic_importance_ = -2; - - // Mark the start of each unit up to the end of this beat group. - for (int unit = 1; unit <= count; unit++) + // Work through the end of the beat group or the end of the beam + while (i < infos_.size () && infos_[i].start_moment_ < next_group_pos) { - Moment next_measure_pos = measure_pos + options.base_moment_; - - while (i < infos_.size () && infos_[i].start_moment_ < next_measure_pos) + Moment dt = infos_[i].start_moment_ - group_pos; + Rational tuplet = infos_[i].factor_; + Moment tuplet_moment (tuplet); + // set the beat end (if not in a tuplet) and increment the next beat + if (tuplet_count == 1 && infos_[i].start_moment_ == next_beat_pos) { - Moment dt = infos_[i].start_moment_ - measure_pos; - - // The rhythmic importance of a stem between beats depends on its fraction - // of a beat: those stems with a lower denominator are deemed more - // important. - // FIXME: This is not the right way to do things for tuplets. For example, - // in an 8th-note triplet with a quarter-note beat, 1/3 of a beat should be - // more important than 1/2. - if (infos_[i].rhythmic_importance_ >= 0) - infos_[i].rhythmic_importance_ = (int) (dt / options.base_moment_).den (); - - i++; + infos_[i].rhythmic_importance_ = -1; + next_beat_pos += options.base_moment_; } + // The rhythmic importance of a stem between beats depends on its fraction + // of a beat: those stems with a lower denominator are deemed more + // important. For tuplets, we need to make sure that we use + // the fraction of the tuplet, instead of the fraction of + // a beat. + Moment ratio = (dt / options.base_moment_ / tuplet_moment); + if (infos_[i].rhythmic_importance_ >= 0) + infos_[i].rhythmic_importance_ = (int) ratio.den (); + i++; + } - measure_pos = next_measure_pos; - if (i < infos_.size () && infos_[i].start_moment_ == measure_pos) + if (i < infos_.size () && infos_[i].start_moment_ == next_beat_pos) + { + if (tuplet_count == 1) infos_[i].rhythmic_importance_ = -1; + next_beat_pos += options.base_moment_; + if (infos_[i].start_moment_ == next_group_pos) + infos_[i].rhythmic_importance_ = -2; + i++; } } } @@ -228,9 +297,9 @@ Beaming_pattern::unbeam_invisible_stems () } void -Beaming_pattern::add_stem (Moment m, int b, bool invisible) +Beaming_pattern::add_stem (Moment m, int b, bool invisible, Rational factor) { - infos_.push_back (Beam_rhythmic_element (m, b, invisible)); + infos_.push_back (Beam_rhythmic_element (m, b, invisible, factor)); } Beaming_pattern::Beaming_pattern () @@ -265,8 +334,14 @@ Beaming_pattern::invisibility (int i) const return infos_.at (i).invisible_; } +Rational +Beaming_pattern::factor (int i) const +{ + return infos_.at (i).factor_; +} + /* - Split a beamin pattern at index i and return a new + Split a beaming pattern at index i and return a new Beaming_pattern containing the removed elements */ Beaming_pattern * @@ -281,7 +356,8 @@ Beaming_pattern::split_pattern (int i) count = max (beamlet_count (j, LEFT), beamlet_count (j, RIGHT)); new_pattern->add_stem (start_moment (j), count, - invisibility (j)); + invisibility (j), + factor (j)); } for (vsize j = i + 1; j < infos_.size ();) infos_.pop_back (); diff --git a/lily/include/beaming-pattern.hh b/lily/include/beaming-pattern.hh index 58ec08443b..1fe990aaa4 100644 --- a/lily/include/beaming-pattern.hh +++ b/lily/include/beaming-pattern.hh @@ -43,7 +43,9 @@ struct Beam_rhythmic_element int rhythmic_importance_; bool invisible_; - Beam_rhythmic_element (Moment, int, bool); + Rational factor_; + + Beam_rhythmic_element (Moment, int, bool, Rational); Beam_rhythmic_element (); int count (Direction d) const; @@ -61,9 +63,10 @@ public: void beamify (Beaming_options const &); void de_grace (); - void add_stem (Moment d, int beams, bool invisible); + void add_stem (Moment d, int beams, bool invisible, Rational factor); int beamlet_count (int idx, Direction d) const; bool invisibility (int idx) const; + Rational factor (int idx) const; Moment start_moment (int idx) const; Moment end_moment (int idx) const; Beaming_pattern *split_pattern (int idx); |