From 49e8c80e3282cefff91ad1b5aaff5d91b443ba5e Mon Sep 17 00:00:00 2001 From: =?utf8?q?Benk=C5=91=20P=C3=A1l?= Date: Sat, 14 Apr 2012 10:21:02 +0200 Subject: [PATCH] Issue 2470: introduce completionUnit enable Completion_heads_engraver to work in sub-bar units --- input/regression/completion-heads-unit.ly | 26 ++++++++++++ lily/completion-note-heads-engraver.cc | 48 +++++++++++++++++++---- scm/define-context-properties.scm | 1 + 3 files changed, 68 insertions(+), 7 deletions(-) create mode 100644 input/regression/completion-heads-unit.ly diff --git a/input/regression/completion-heads-unit.ly b/input/regression/completion-heads-unit.ly new file mode 100644 index 0000000000..af3152b6f5 --- /dev/null +++ b/input/regression/completion-heads-unit.ly @@ -0,0 +1,26 @@ +\version "2.15.37" + +\header { +texidoc = " +Note head completion may be broken into sub-bar units by setting the +@code{completionUnit} property. +" +} + +\layout { + \context { + \Voice + \remove "Note_heads_engraver" + \consists "Completion_heads_engraver" + } +} + +\context Staff \relative f { + \time 9/8 + \set completionUnit = #(ly:make-moment 3 8) + g'1.. g2 + \time 6/4 + \set completionUnit = #(ly:make-moment 1 4) + \set tupletSpannerDuration = #(ly:make-moment 1 4) + \times 2/3 { e4 c8 f g a4 b8 c4 b8 a4 g8 a e f4 } +} diff --git a/lily/completion-note-heads-engraver.cc b/lily/completion-note-heads-engraver.cc index 64705a4abd..973fb4f28d 100644 --- a/lily/completion-note-heads-engraver.cc +++ b/lily/completion-note-heads-engraver.cc @@ -35,6 +35,7 @@ using namespace std; #include "tie.hh" #include "tie-column.hh" #include "warn.hh" +#include "misc.hh" #include "translator.icc" @@ -47,7 +48,7 @@ using namespace std; Every time process_music () is called and there are note events, we figure out how long the note to typeset should be. It should be no longer than what's specified, than what is left to do and it should - not cross barlines. + not cross barlines or sub-bar units. We copy the events into scratch note events, to make sure that we get all durations exactly right. @@ -69,7 +70,7 @@ class Completion_heads_engraver : public Engraver Rational do_nothing_until_; Rational factor_; - Moment next_barline_moment (); + Moment next_moment (Rational const &); Item *make_note_head (Stream_event *); public: @@ -105,10 +106,10 @@ Completion_heads_engraver::listen_note (Stream_event *ev) } /* - The duration _until_ the next bar line. + The duration _until_ the next bar line or completion unit */ Moment -Completion_heads_engraver::next_barline_moment () +Completion_heads_engraver::next_moment (Rational const ¬e_len) { Moment *e = unsmob_moment (get_property ("measurePosition")); Moment *l = unsmob_moment (get_property ("measureLength")); @@ -117,7 +118,40 @@ Completion_heads_engraver::next_barline_moment () return Moment (0, 0); } - return (*l - *e); + Moment result = *l - *e; + Moment const *unit = unsmob_moment (get_property ("completionUnit")); + + if (unit) + { + Rational const now_unit = e->main_part_ / unit->main_part_; + if (now_unit.den() > 1) + { + /* + within a unit - go to the end of that + */ + result = unit->main_part_ + * (Rational (1) - (now_unit - now_unit.trunc_rat ())); + } + else + { + /* + at the beginning of a unit: + take a power-of-two number of units, but not more than required, + since then the Duration constructor destroys the unit structure + */ + if (note_len < result.main_part_) + result.main_part_ = note_len; + Rational const step_unit = result.main_part_ / unit->main_part_; + if (step_unit.den () < step_unit.num ()) + { + int const log2 + = intlog2 (int (step_unit.num () / step_unit.den ())); + result.main_part_ = unit->main_part_ * Rational (1 << log2); + } + } + } + + return result; } Item * @@ -168,10 +202,10 @@ Completion_heads_engraver::process_music () factor_ = note_dur.factor (); left_to_do_ = orig->get_length (); } - Moment nb = next_barline_moment (); + Moment nb = next_moment (note_dur.get_length ()); if (nb.main_part_ && nb < note_dur.get_length ()) { - if (factor_.denominator () == 1 && factor_ > Rational (1, 1)) + if (factor_.denominator () == 1 && factor_.numerator () > 1) note_dur = Duration (nb.main_part_, false); else note_dur = Duration (nb.main_part_ / factor_, false).compressed (factor_); diff --git a/scm/define-context-properties.scm b/scm/define-context-properties.scm index ff29b144c9..15c717ffd1 100644 --- a/scm/define-context-properties.scm +++ b/scm/define-context-properties.scm @@ -177,6 +177,7 @@ Values of 7 and -7 are common.") symbol go, measured in half staff spaces from the center of the staff.") (completionBusy ,boolean? "Whether a completion-note head is playing.") + (completionUnit ,ly:moment? "Sub-bar unit of completion.") (connectArpeggios ,boolean? "If set, connect arpeggios across piano staff.") (countPercentRepeats ,boolean? "If set, produce counters for -- 2.39.5