From 41a62252880c2e61c88da32a45db3246d0d1fbfa Mon Sep 17 00:00:00 2001 From: hanwen Date: Sat, 3 Aug 2002 00:43:19 +0000 Subject: [PATCH] * lily/beam.cc (consider_auto_knees): rewrite function; now only consider horizontal knees. Fixes input/bugs/bizzarre-beam.ly * lily/syllable-group.cc (set_lyric_align): fix centering on note head for `normal' lyrics. This fixes input/bugs/lyrics-spacing.ly. --- ChangeLog | 8 + Documentation/user/tutorial.itely | 4 + GNUmakefile.in | 7 + input/bugs/bizarre-beam.ly | 11 - input/bugs/divisi-staff.ly | 28 --- input/bugs/knee.ly | 18 -- input/bugs/lyrics-bar.ly | 47 ---- input/bugs/lyrics-spacing.ly | 27 --- input/bugs/markup-definition.ly | 26 --- input/bugs/rest-melisma.ly | 10 +- input/bugs/slur-attachment.ly | 21 -- input/bugs/slur-dx.ly | 19 -- input/bugs/slur-steep-broken.ly | 17 -- input/regression/auto-knee.ly | 12 +- lily/beam.cc | 183 ++++++++++++---- lily/include/lyric-phrasing-engraver.hh | 4 +- lily/lyric-phrasing-engraver.cc | 33 ++- lily/syllable-group.cc | 279 +++++++++++++----------- scm/c++.scm | 4 - scm/grob-description.scm | 6 +- scm/grob-property-description.scm | 3 +- stepmake/stepmake/generic-targets.make | 3 + 22 files changed, 355 insertions(+), 415 deletions(-) delete mode 100644 input/bugs/bizarre-beam.ly delete mode 100644 input/bugs/divisi-staff.ly delete mode 100644 input/bugs/knee.ly delete mode 100644 input/bugs/lyrics-bar.ly delete mode 100644 input/bugs/lyrics-spacing.ly delete mode 100644 input/bugs/markup-definition.ly delete mode 100644 input/bugs/slur-attachment.ly delete mode 100644 input/bugs/slur-dx.ly delete mode 100644 input/bugs/slur-steep-broken.ly diff --git a/ChangeLog b/ChangeLog index 7cd2ccfb0c..0571e8f02c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2002-08-03 Han-Wen + + * lily/beam.cc (consider_auto_knees): rewrite function; now only + consider horizontal knees. Fixes input/bugs/bizzarre-beam.ly + + * lily/syllable-group.cc (set_lyric_align): fix centering on note + head for `normal' lyrics. This fixes input/bugs/lyrics-spacing.ly. + 2002-08-02 Han-Wen * lily/beam.cc (connect_beams): fix quarter note beams. diff --git a/Documentation/user/tutorial.itely b/Documentation/user/tutorial.itely index a8dc14a6a1..cdc4d0ef51 100644 --- a/Documentation/user/tutorial.itely +++ b/Documentation/user/tutorial.itely @@ -1468,6 +1468,10 @@ surround dots with spaces in @code{\lyrics} mode. \property LyricsVoice . stanza = "Ernie" @end example +The convention for naming @code{LyricsVoice} and @code{Voice} must +also be used to get melismata on rests correct. + + @node More movements @section More movements diff --git a/GNUmakefile.in b/GNUmakefile.in index d3faf38932..16aa3d02ec 100644 --- a/GNUmakefile.in +++ b/GNUmakefile.in @@ -66,6 +66,13 @@ ifeq ($(KPATHSEA),0) endif +final-install: + @echo + @echo " *** Before running, buildscripts/out/lilypond-{profile,login}" + @echo " *** must be run. You're advised to source these scripts from your " + @echo " *** login scripts. For more information, see Invoking LilyPond in the manual." + @echo + TOP_HTMLS = index.html examples.html examples: web-reqs diff --git a/input/bugs/bizarre-beam.ly b/input/bugs/bizarre-beam.ly deleted file mode 100644 index b1abf20a70..0000000000 --- a/input/bugs/bizarre-beam.ly +++ /dev/null @@ -1,11 +0,0 @@ - - -\score{ \notes {g''4 [ g''] -\notes\relative c'{ - - \times 2/3{[d16 fis' d,]} \times 2/3{[cis g'' cis,,]} - a'16 cis a, g''' % Used to give a nice beam directed upwards. - <{\stemUp a,,4:32} \context Voice=lower{\stemDown d,:32}> - -} - }} diff --git a/input/bugs/divisi-staff.ly b/input/bugs/divisi-staff.ly deleted file mode 100644 index 1c5673dac7..0000000000 --- a/input/bugs/divisi-staff.ly +++ /dev/null @@ -1,28 +0,0 @@ -% -% space after barline on 1st staff due to time sig. -% - -\score{ - \notes\relative c'\context GrandStaff{ - -c4 d e f | -g a b c | \break - -<{ -d c b a | - g f e d} - \context Staff=lower{ -% \property Staff.TimeSignature = \turnOff - -b' a g f | - e d c b |}> \break - -c1 -} -\paper{ - \translator{ - \GrandStaffContext - \consists "Instrument_name_engraver" - } -} -} diff --git a/input/bugs/knee.ly b/input/bugs/knee.ly deleted file mode 100644 index 02f3524bff..0000000000 --- a/input/bugs/knee.ly +++ /dev/null @@ -1,18 +0,0 @@ -\header { - -texidoc=" Funky kneed beams with beamlets also work. The beamlets -should be pointing to the note head. -" - -} - -\score { - \notes\relative c' { - c16 c''8 c,,16 - c16 c''8 c16 - c16 c,,8 c16 - - } - \paper { linewidth = -1 } -} - diff --git a/input/bugs/lyrics-bar.ly b/input/bugs/lyrics-bar.ly deleted file mode 100644 index 2170b9ff15..0000000000 --- a/input/bugs/lyrics-bar.ly +++ /dev/null @@ -1,47 +0,0 @@ -\version "1.5.68" - -% -% - -\header{ -texidoc = " -Adding a @code{Bar_engraver} to the LyricsVoice context makes sure that -lyrics don't collide with barlines. - -Lyrics with barline colliding is fine now, BUT -There's an horizontal gap between staff and end bar . -" -} - -\score { - \context StaffGroup < - \notes \context Staff { - b1 \bar "|:" b1 \bar ":|" - } - \lyrics\context Lyrics < - \context LyricsVoiceWithBars { -% thisContextHasBarEngraver1 added - ThisContextCertainlyHasBarEngraverAddedButThereHasBeenSomethingFunnyBefore1. Here. - } - \context LyricsVoice { - this4 one has no BarEngraverAddedToContext1 - } - > - \notes \context Staff = SB { b1 b1 } - > - \paper { - linewidth = -1.0\cm - \translator { - \LyricsContext - \accepts "LyricsVoiceWithBars" - } - \translator { - \LyricsVoiceContext - \consists "Bar_engraver" - \name "LyricsVoiceWithBars" - } - \translator { - \LyricsVoiceContext - } - } -} diff --git a/input/bugs/lyrics-spacing.ly b/input/bugs/lyrics-spacing.ly deleted file mode 100644 index cabb282f7a..0000000000 --- a/input/bugs/lyrics-spacing.ly +++ /dev/null @@ -1,27 +0,0 @@ -\include "norsk.ly" - -\header { -texidoc ="``baz'' should be centered on the a (tenor voice), but it is -not." -} - -\version "1.5.68" - -sop = \notes \transpose c'' {e2 e fis1 } -alt = \notes \relative c' {cis2 e e d } -ten = \notes \relative c' {a2 a a1 } -txt = \lyrics {foo2 bar baz jazz } - -\score { - < - \context Staff = up \notes < - \context Voice=sopv {\stemUp \sop} - \context Voice=altv {\stemDown \alt} - > - \context Staff = down \notes < \clef "F" - \context Voice=tenv {\stemUp \ten} - > - \context Lyrics = la { \txt } - > - \paper { linewidth = -1 } -} diff --git a/input/bugs/markup-definition.ly b/input/bugs/markup-definition.ly deleted file mode 100644 index ff2a6162c5..0000000000 --- a/input/bugs/markup-definition.ly +++ /dev/null @@ -1,26 +0,0 @@ -\version "1.5.68" -\header { - -texidoc=" -The definition of markup is incomplete. - -Ideally, either the input is valid, and all information therein is -used, or it is invalid, and an error message is produced." - -} - - -\score { \notes \relative c' { - f_#'(lines "one" ( "tow")) - - % FIXED:three ignored - f_#'(lines "one" ( "two" "three" )) - - % right way of using multiple markups - f_#'(lines "one" ((bold italic) "towo")) - - % italic ignored. - % possibly explicit relaxed code for chords stuff, must check - f_#'(lines "one" (bold italic "towo")) - - }} diff --git a/input/bugs/rest-melisma.ly b/input/bugs/rest-melisma.ly index 762b782efe..5f53d42350 100644 --- a/input/bugs/rest-melisma.ly +++ b/input/bugs/rest-melisma.ly @@ -7,14 +7,14 @@ texidoc = "slur or long note on other staves fool lily into extending melisma" \addlyrics \notes { \property Staff.automaticMelismata= ##t - c4 () c r c + \context Voice = melismaBla { c4 () c r c } } - \context Lyrics \lyrics { foo __ bar } + \context LyricsVoice = "melismaBla-1" \lyrics { foo __ bar } \context Staff=foolMelismata \notes{ - c4 ( c c ) c + c4 c c c } - \context Staff=foolMelismata \notes{ + \context Staff=OtherFoolMelismata \notes{ c1 } > -} \ No newline at end of file +} diff --git a/input/bugs/slur-attachment.ly b/input/bugs/slur-attachment.ly deleted file mode 100644 index 8a21d68765..0000000000 --- a/input/bugs/slur-attachment.ly +++ /dev/null @@ -1,21 +0,0 @@ -\version "1.5.68" - -\header{ -texidoc = " -Slurs should be attached to note heads, except when they would collide -with beams. Also see: ophee-slurs. -" -} -\score{ - \notes \relative c''{ - \property Voice.Slur \set #'direction = #1 - a8( a )a4 - a4( a8 )a - a8 a()a4 - a4() a8 a - } - \paper{ - indent = 0.0 - linewidth = 100.\mm - } -} diff --git a/input/bugs/slur-dx.ly b/input/bugs/slur-dx.ly deleted file mode 100644 index ed15d3bd1f..0000000000 --- a/input/bugs/slur-dx.ly +++ /dev/null @@ -1,19 +0,0 @@ -\version "1.5.68" - -\header{ -texidoc = " - Wouldbe-steep-starting slurs look ugly. -" } - -\score { - \notes \relative c'' { - \property Voice.Stem \set #'direction = #1 - \property Voice.Slur \set #'direction = #1 - d,32( d'4 )d8.. - \property Voice.Slur \set #'attachment = #'(stem . stem) - d,32( d'4 )d8.. - } - \paper { - linewidth = -1. - } -} diff --git a/input/bugs/slur-steep-broken.ly b/input/bugs/slur-steep-broken.ly deleted file mode 100644 index 78b6301af0..0000000000 --- a/input/bugs/slur-steep-broken.ly +++ /dev/null @@ -1,17 +0,0 @@ - -% ?? - -\version "1.5.68" - -\score{ - \notes\relative c''{ - \time 2/4 - [f8 e d f, (] | \break - [) a'8. gis16 fis8. cis16] | - } - \paper{ - linewidth = 3.5\cm - indent = .0 - } -} - diff --git a/input/regression/auto-knee.ly b/input/regression/auto-knee.ly index 6cfd2f50bd..fc72a3d009 100644 --- a/input/regression/auto-knee.ly +++ b/input/regression/auto-knee.ly @@ -1,19 +1,17 @@ \version "1.5.68" -\header{ -texidoc="One automatic knee" +\header{ texidoc="Automatic kneeing. A knee is made when a horizontal +beam fits in a gap between note heads that is larger than a predefined +threshold. +" } \score { \context Staff \notes\relative c''{ [c'8 c,,] [c8 e'] + [c,16 e g c e g c c,,] } \paper{ linewidth = 40*\staffspace -% Now by default -% \translator { -% \VoiceContext -% Beam \override #'auto-knee-gap = #7 -% } } } diff --git a/lily/beam.cc b/lily/beam.cc index 695a704750..43c7d7a9ca 100644 --- a/lily/beam.cc +++ b/lily/beam.cc @@ -559,77 +559,170 @@ Beam::set_stem_directions (Grob *me, Direction d) } } -/* Simplistic auto-knees; only consider vertical gap between two - adjacent chords. +/* + A union of intervals in the real line. + + Abysmal performance (quadratic) for large N, hopefully we don't have + that large N. In any case, this should probably be rewritten to use + a balanced tree. + */ +struct Int_set +{ + Array allowed_regions_; - This may decide for a knee that's impossible to fit sane scoring - criteria (eg, stem lengths). We may need something smarter. */ + Int_set() + { + set_full(); + } + + void set_full() + { + allowed_regions_.clear(); + Interval s; + s.set_full (); + allowed_regions_.push (s); + } + + void remove_interval (Interval rm) + { + for (int i = 0; i < allowed_regions_.size(); ) + { + Interval s = rm; + + s.intersect (allowed_regions_[i]); + + if (!s.empty_b ()) + { + Interval before = allowed_regions_[i]; + Interval after = allowed_regions_[i]; + + before[RIGHT] = s[LEFT]; + after[LEFT] = s[RIGHT]; + + if (!before.empty_b()) + { + allowed_regions_.insert (before, i); + i++; + } + allowed_regions_.del (i); + if (!after.empty_b ()) + { + allowed_regions_.insert (after, i); + i++; + } + } + else + i++; + } + } +}; + + +/* + Only try horizontal beams for knees. No reliable detection of + anything else is possible here, since we don't know funky-beaming + settings, or X-distances (slopes!) People that want sloped + knee-beams, should set the directions manually. + */ void -Beam::consider_auto_knees (Grob *me, Direction d) +Beam::consider_auto_knees (Grob* me, Direction d) { SCM scm = me->get_grob_property ("auto-knee-gap"); - if (!gh_number_p (scm)) - return; + return ; + + Real threshold = gh_scm2double (scm); - bool knee_b = false; + Int_set gaps; + + gaps.set_full (); - Real staff_space = Staff_symbol_referencer::staff_space (me); - Real gap = gh_scm2double (scm) / staff_space; Link_array stems= Pointer_group_interface__extract_grobs (me, (Grob*)0, "stems"); Grob *common = common_refpoint_of_array (stems, me, Y_AXIS); - - int l = 0; - for (int r=1; r < stems.size (); r++) + Real staff_space = Staff_symbol_referencer::staff_space (me); + + Array hps_array; + for (int i=0; i < stems.size (); i++) { - if (!Stem::invisible_b (stems[r-1])) - l = r - 1; - Grob *right = stems[r]; - Grob *left = stems[l]; - if (Stem::invisible_b (left)) + Grob* stem = stems[i]; + if (Stem::invisible_b (stem)) continue; - if (Stem::invisible_b (right)) - continue; - - Real left_y = Stem::extremal_heads (left)[d] - ->relative_coordinate (common, Y_AXIS); - Real right_y = Stem::extremal_heads (right)[-d] - ->relative_coordinate (common, Y_AXIS); + - Real dy = right_y - left_y; + Interval hps = Stem::head_positions (stem); - if (abs (dy) >= gap) + if(!hps.empty_b()) { - knee_b = true; - Direction knee_dir = (right_y > left_y ? UP : DOWN); - if (!Stem::invisible_b (left) - && left->get_grob_property ("dir-forced") != SCM_BOOL_T) - { - Directional_element_interface::set (left, knee_dir); - left->set_grob_property ("dir-forced", SCM_BOOL_T); - - } - if (!Stem::invisible_b (right) - && stems[r]->get_grob_property ("dir-forced") != SCM_BOOL_T) + hps[LEFT] += -1; + hps[RIGHT] += 1; + hps *= staff_space * 0.5 ; + hps += stem->relative_coordinate (common, Y_AXIS); + + if (to_boolean (stem->get_grob_property ("dir-forced"))) { - Directional_element_interface::set (right, -knee_dir); - right->set_grob_property ("dir-forced", SCM_BOOL_T); + Direction stemdir =Directional_element_interface::get (stem); + hps[-stemdir] = - stemdir * infinity_f; } } + hps_array.push (hps); + + gaps.remove_interval (hps); } - if (knee_b) + Interval max_gap; + Real max_gap_len =0.0; + + for (int i = gaps.allowed_regions_.size() -1; i >= 0 ; i--) { - me->set_grob_property ("knee", SCM_BOOL_T); - - for (int i=0; i < stems.size (); i++) - stems[i]->set_grob_property ("stem-info", SCM_EOL); + Interval gap = gaps.allowed_regions_[i]; + + /* + the outer gaps are not knees. + */ + if (isinf (gap[LEFT]) || isinf(gap[RIGHT])) + continue; + + if (gap.length () >= max_gap_len) + { + max_gap_len = gap.length(); + max_gap = gap; + } + } + + if (max_gap_len > threshold) + { + int j = 0; + for (int i = 0; i < stems.size(); i++) + { + Grob* stem = stems[i]; + if (Stem::invisible_b (stem)) + continue; + + Interval hps = hps_array[j++]; + + + Direction d = (hps.center () < max_gap.center()) ? + UP : DOWN ; + + stem->set_grob_property ("direction", gh_int2scm (d)); + + /* + UGH. Check why we still need dir-forced; I think we can + junk it. + */ + stem->set_grob_property ("dir-forced", SCM_BOOL_T); + + hps.intersect (max_gap); + assert (hps.empty_b () || hps.length () < 1e-6 ); + } } } + + /* Set stem's shorten property if unset. TODO: diff --git a/lily/include/lyric-phrasing-engraver.hh b/lily/include/lyric-phrasing-engraver.hh index d3a8339d2a..48ad83a32e 100644 --- a/lily/include/lyric-phrasing-engraver.hh +++ b/lily/include/lyric-phrasing-engraver.hh @@ -94,7 +94,7 @@ class Syllable_group { bool first_in_phrase_b_; Grob * notehead_; - Link_array lyric_list_; + Link_array lyrics_; Grob * longest_lyric_; Grob * shortest_lyric_; int alignment_; @@ -108,7 +108,7 @@ public: void add_extender (Grob * extender); void set_melisma () { melisma_b_ = true; } bool get_melisma () { return melisma_b_; } - int lyric_count () { return lyric_list_.size (); } + int lyric_count () { return lyrics_.size (); } void clear (); bool is_empty (); bool set_lyric_align (const char *punc, Grob *default_notehead); diff --git a/lily/lyric-phrasing-engraver.cc b/lily/lyric-phrasing-engraver.cc index 483d85d2c4..5db329f479 100644 --- a/lily/lyric-phrasing-engraver.cc +++ b/lily/lyric-phrasing-engraver.cc @@ -112,12 +112,15 @@ Lyric_phrasing_engraver::lookup_context_id (const String &context_id) /* match found */ // (key . ((alist_entry . old_entry) . previous_entry)) if (to_boolean (ly_cdadr (s))) - { // it's an old entry ... make it a new one + { + // it's an old entry ... make it a new one SCM val = gh_cons (gh_cons (ly_caadr (s), SCM_BOOL_F), ly_cddr (s)); voice_alist_ = scm_assoc_set_x (voice_alist_, ly_car (s), val); return unsmob_voice_entry (ly_caar (val)); } - else { // the entry is current ... return it. + else + { + // the entry is current ... return it. SCM entry_scm = ly_caadr (s); return unsmob_voice_entry (entry_scm); } @@ -176,7 +179,12 @@ Lyric_phrasing_engraver::record_melisma (const String &context_id) Syllable_group * v = lookup_context_id (context_id); v->set_melisma (); } - + +/* + TODO: this engraver is always on, also for orchestral scores. That + is a waste of time and space. This should be switched on + automatically at the first Lyrics found. + */ void Lyric_phrasing_engraver::acknowledge_grob (Grob_info i) { @@ -214,10 +222,11 @@ Lyric_phrasing_engraver::acknowledge_grob (Grob_info i) { voice_context_id = ly_scm2string (voice_context_scm); } - else { - voice_context_id = get_context_id (i.origin_trans_->daddy_trans_, "LyricsVoice"); - voice_context_id = trim_suffix (voice_context_id); - } + else + { + voice_context_id = get_context_id (i.origin_trans_->daddy_trans_, "LyricsVoice"); + voice_context_id = trim_suffix (voice_context_id); + } record_lyric (voice_context_id, h); return; } @@ -291,7 +300,8 @@ Lyric_phrasing_engraver::process_acknowledged_grobs () SCM v_entry = ly_cdar (v); // ((current . oldflag) . previous) if (!to_boolean (ly_cdar (v_entry))) - { // not an old entry left over from a prior note ... + { + // not an old entry left over from a prior note ... Syllable_group *entry = unsmob_voice_entry (ly_caar (v_entry)); /* @@ -344,7 +354,12 @@ Lyric_phrasing_engraver::stop_translation_timestep () ENTER_DESCRIPTION(Lyric_phrasing_engraver, - /* descr */ "", + /* descr */ " +This engraver combines note heads and lyrics for alignment. + +This engraver is switched on by default. Turn it off for faster +processing of orchestral scores. +", /* creats*/ "", /* acks */ "lyric-syllable-interface note-head-interface lyric-extender-interface", /* reads */ "automaticPhrasing melismaEngraverBusy associatedVoice phrasingPunctuation", diff --git a/lily/syllable-group.cc b/lily/syllable-group.cc index 1650fd94af..909a296bde 100644 --- a/lily/syllable-group.cc +++ b/lily/syllable-group.cc @@ -9,10 +9,9 @@ #include "paper-def.hh" -/*=========================================================================================*/ - -/** Syllable_group is a class to be smobbed and entered as data in the association list - member of the Lyric_phrasing_engraver class. +/* + Syllable_group is a class to be smobbed and entered as data in the + association list member of the Lyric_phrasing_engraver class. */ Syllable_group::Syllable_group () @@ -26,7 +25,7 @@ void Syllable_group::clear () { notehead_=0; - lyric_list_.clear (); + lyrics_.clear (); longest_lyric_=0; shortest_lyric_=0; melisma_b_ = false; @@ -37,7 +36,7 @@ void Syllable_group::copy (Syllable_group *from) { notehead_ = from->notehead_; - lyric_list_ = from->lyric_list_; + lyrics_ = from->lyrics_; longest_lyric_ = from->longest_lyric_; shortest_lyric_ = from->shortest_lyric_; melisma_b_ = from->melisma_b_; @@ -55,23 +54,26 @@ Syllable_group::set_first_in_phrase (bool f) void Syllable_group::set_notehead (Grob * notehead) { - if (!notehead_) { - /* there should only be a single notehead, so silently ignore any extras */ - notehead_=notehead; - } + if (!notehead_) + { + /* there should only be a single notehead, so silently ignore + any extras */ + notehead_=notehead; + } } void Syllable_group::add_lyric (Grob * lyric) { - lyric_list_.push (lyric); + lyrics_.push (lyric); /* record longest and shortest lyrics */ - if (longest_lyric_) { - if (lyric->extent (lyric,X_AXIS).length () > (longest_lyric_->extent (longest_lyric_, X_AXIS)).length ()) - longest_lyric_ = lyric; - if (lyric->extent (lyric, X_AXIS).length () < (shortest_lyric_->extent (shortest_lyric_, X_AXIS)).length ()) - shortest_lyric_ = lyric; - } + if (longest_lyric_) + { + if (lyric->extent (lyric,X_AXIS).length () > (longest_lyric_->extent (longest_lyric_, X_AXIS)).length ()) + longest_lyric_ = lyric; + if (lyric->extent (lyric, X_AXIS).length () < (shortest_lyric_->extent (shortest_lyric_, X_AXIS)).length ()) + shortest_lyric_ = lyric; + } else longest_lyric_ = shortest_lyric_ = lyric; } @@ -79,100 +81,116 @@ Syllable_group::add_lyric (Grob * lyric) void Syllable_group::add_extender (Grob * extender) { - if (notehead_ && melisma_b_) { - dynamic_cast (extender)->set_bound (RIGHT, notehead_); - // should the extender finish at the right of the last note of the melisma, or the left? - // Comments in lyric-extender.hh say left, but right looks better to me. GP. - - // Left: -// extender->set_grob_property ("right-trim-amount", gh_double2scm (0.0)); - - // Right: - Real ss = 1.0; - extender->set_grob_property ("right-trim-amount", - gh_double2scm (-notehead_->extent (notehead_, X_AXIS).length ()/ss)); - } + if (notehead_ && melisma_b_) + { + dynamic_cast (extender)->set_bound (RIGHT, notehead_); + // should the extender finish at the right of the last note of the melisma, or the left? + // Comments in lyric-extender.hh say left, but right looks better to me. GP. + + // Left: + // extender->set_grob_property ("right-trim-amount", gh_double2scm (0.0)); + + // Right: + Real ss = 1.0; + extender->set_grob_property ("right-trim-amount", + gh_double2scm (-notehead_->extent (notehead_, X_AXIS).length ()/ss)); + } } bool Syllable_group::set_lyric_align (const char *punc, Grob *default_notehead) { - if (lyric_list_.size ()<=1) { - // No lyrics or single line: nothing to do. - return true; - } + if (lyrics_.size ()<=1) + { + // No lyrics or single line: nothing to do. + return true; + } Grob * lyric; alignment_ = appropriate_alignment (punc); - // If there was no notehead in the matching voice context, use the first - // notehead caught from any voice context (any port in a storm). - if (!notehead_) { - notehead_ = default_notehead; - } + /* If there was no notehead in the matching voice context, use the + first notehead caught from any voice context (any port in a storm). + + + Is this wise? Can't the lyric simply be set on a the paper-column, + and be done with it. That's just as correct, and won't give strange + results if the port-in-the-storms happesn to be involved in a + note-collision? --hwn. + */ + if (!notehead_) + { + notehead_ = default_notehead; + } group_translation_ = amount_to_translate (); // set the x alignment of each lyric - for (int l = 0; l < lyric_list_.size (); l++) { - lyric = lyric_list_[l]; - lyric->set_grob_property ("self-alignment-X", gh_int2scm (alignment_)); - // centre on notehead ... if we have one. - if (notehead_) { - lyric->set_parent (notehead_, X_AXIS); - lyric->add_offset_callback (Self_alignment_interface::centered_on_parent_proc, X_AXIS); - // reference is on the right of the notehead; move it left half way, and add translation - lyric->translate_axis (group_translation_- (notehead_->extent (notehead_, X_AXIS)).center (), X_AXIS); + for (int l = 0; l < lyrics_.size (); l++) + { + lyric = lyrics_[l]; + lyric->set_grob_property ("self-alignment-X", gh_int2scm (alignment_)); + if (notehead_) + { + /* + Centering on parent is done by default (see + grob-description.scm); we only have to set the parent. + */ + lyric->set_parent (notehead_, X_AXIS); + lyric->translate_axis (group_translation_, X_AXIS); + } } - } return (notehead_); } /** determine the distance to translate lyrics to get correct alignment Rules: If alignment is centre, translate = 0 - Otherwise, - If (length of longest lyric) < (property {begin,end}-alignment) * (length of shortest lyric), - - centre longest lyric on notehead - Otherwise - - move so shortest lyric just reaches notehead centre + Otherwise, + If (length of longest lyric) < (property {begin,end}-alignment) * (length of shortest lyric), + - centre longest lyric on notehead + Otherwise + - move so shortest lyric just reaches notehead centre */ Real Syllable_group::amount_to_translate () { Real translate = 0.0; - if (alignment_ != CENTER) { - switch (alignment_) { - // FIXME: do we really know the lyric extent here? Some font sizing comes later? - case LEFT: - translate = longest_lyric_->extent (longest_lyric_, X_AXIS).length () / gh_scm2double (longest_lyric_->get_grob_property("begin-alignment")); - break; - case RIGHT: - translate = longest_lyric_->extent (longest_lyric_, X_AXIS).length () / gh_scm2double (longest_lyric_->get_grob_property("end-alignment")); - break; - } - if (!gh_scm2bool(longest_lyric_->get_grob_property("ignore-length-mismatch"))) { - Real l = shortest_lyric_->extent (shortest_lyric_, X_AXIS).length (); - translate = l extent (longest_lyric_, X_AXIS).length () / gh_scm2double (longest_lyric_->get_grob_property("begin-alignment")); + break; + case RIGHT: + translate = longest_lyric_->extent (longest_lyric_, X_AXIS).length () / gh_scm2double (longest_lyric_->get_grob_property("end-alignment")); + break; + } + if (!gh_scm2bool(longest_lyric_->get_grob_property("ignore-length-mismatch"))) + { + Real l = shortest_lyric_->extent (shortest_lyric_, X_AXIS).length (); + translate = l longest_lyric_->get_grob_property ("alignment"); - if (s!=SCM_EOL) { + if (s!=SCM_EOL) + { return gh_scm2int (s); } @@ -182,39 +200,45 @@ Syllable_group::appropriate_alignment (const char *punc) Grob * lyric; bool end_phrase = true; - for (int l = 0; l < lyric_list_.size () && end_phrase; l++) { - lyric = lyric_list_[l]; - SCM lyric_scm = lyric->get_grob_property ("text"); - String lyric_string = gh_string_p (lyric_scm)?ly_scm2string (lyric_scm):""; - char lastchar; - if (lyric_string.length ()>0) { - lastchar = lyric_string[lyric_string.length ()-1]; - /* If it doesn't end in punctuation then it ain't an end of phrase */ - if (! strchr (punc, lastchar)) { - /* - FIXME: Document this. + for (int l = 0; l < lyrics_.size () && end_phrase; l++) + { + lyric = lyrics_[l]; + SCM lyric_scm = lyric->get_grob_property ("text"); + String lyric_string = gh_string_p (lyric_scm)?ly_scm2string (lyric_scm):""; + char lastchar; + if (lyric_string.length ()>0) + { + lastchar = lyric_string[lyric_string.length ()-1]; + /* If it doesn't end in punctuation then it ain't an end of phrase */ + if (! strchr (punc, lastchar)) + { + /* + FIXME: Document this. - Special case: trailing space. Here examine the previous character and reverse the - sense of the test (i.e. trailing space makes a break without punctuation, or - suppresses a break with punctuation). - This behaviour can be suppressed by including a space in the - phrasingPunctuation property, in which case trailing space always means - the same as punctuation. - - FIXME: The extra space throws alignment out a bit. - */ - if (lastchar == ' ') { - if (lyric_string.length ()>1) { - lastchar = lyric_string[lyric_string.length ()-2]; - if (strchr (punc, lastchar)) - end_phrase=false; - } + Special case: trailing space. Here examine the + previous character and reverse the sense of the test + (i.e. trailing space makes a break without + punctuation, or suppresses a break with punctuation). + This behaviour can be suppressed by including a space + in the phrasingPunctuation property, in which case + trailing space always means the same as punctuation. + + FIXME: The extra space throws alignment out a bit. + */ + if (lastchar == ' ') + { + if (lyric_string.length ()>1) + { + lastchar = lyric_string[lyric_string.length ()-2]; + if (strchr (punc, lastchar)) + end_phrase=false; + } + } + else + end_phrase=false; + } } - else - end_phrase=false; - } } - } if (end_phrase) return RIGHT; @@ -227,31 +251,34 @@ Syllable_group::appropriate_alignment (const char *punc) void Syllable_group::adjust_melisma_align () { - if (notehead_ && lyric_list_.size ()) { - // override any previous offset adjustments - Real translation = -group_translation_; - // melisma aligning: - switch (alignment_) { - // case LEFT: // that's all - case CENTER: // move right so smallest lyric is left-aligned on notehead - translation += (shortest_lyric_->extent (shortest_lyric_, X_AXIS)).length ()/2; - break; - case RIGHT: // move right so smallest lyric is left-aligned on notehead - translation += (shortest_lyric_->extent (shortest_lyric_, X_AXIS)).length (); - break; - } - group_translation_ += translation; - for (int l = 0; l < lyric_list_.size (); l++) { - lyric_list_[l]->translate_axis (translation, X_AXIS); + if (notehead_ && lyrics_.size ()) + { + // override any previous offset adjustments + Real translation = -group_translation_; + // melisma aligning: + switch (alignment_) + { + // case LEFT: // that's all + case CENTER: // move right so smallest lyric is left-aligned on notehead + translation += (shortest_lyric_->extent (shortest_lyric_, X_AXIS)).length ()/2; + break; + case RIGHT: // move right so smallest lyric is left-aligned on notehead + translation += (shortest_lyric_->extent (shortest_lyric_, X_AXIS)).length (); + break; + } + group_translation_ += translation; + for (int l = 0; l < lyrics_.size (); l++) + { + lyrics_[l]->translate_axis (translation, X_AXIS); + } } - } } bool Syllable_group::is_empty () { - return lyric_list_.size ()==0; + return lyrics_.size ()==0; } void @@ -288,9 +315,9 @@ Syllable_group::make_entry () struct Lyric_syllable { - static bool has_interface (Grob*); + static bool has_interface (Grob*); }; ADD_INTERFACE (Lyric_syllable,"lyric-syllable-interface", - "a single piece of lyrics", - "word-space alignment ignore-length-mismatch begin-alignment end-alignment"); + "a single piece of lyrics", + "word-space alignment ignore-length-mismatch begin-alignment end-alignment"); diff --git a/scm/c++.scm b/scm/c++.scm index 58d6222636..41bd34139e 100644 --- a/scm/c++.scm +++ b/scm/c++.scm @@ -24,9 +24,6 @@ (define (boolean-or-symbol? x) (or (boolean? x) (symbol? x))) -(define (number-or-boolean? x) - (or (number? x) (boolean? x))) - (define (number-or-string? x) (or (number? x) (string? x))) @@ -62,7 +59,6 @@ (,procedure? . "procedure") (,boolean-or-symbol? . "boolean or symbol") (,number-or-string? . "number or string") - (,number-or-boolean? . "number or boolean") (,markup? . "markup (list or string)") (,number-or-grob? . "number or grob") )) diff --git a/scm/grob-description.scm b/scm/grob-description.scm index cdc3f05145..3b9790090c 100644 --- a/scm/grob-description.scm +++ b/scm/grob-description.scm @@ -146,7 +146,7 @@ (slope-limit . 0.2) (flag-width-function . ,default-beam-flag-width-function) (damping . 1) - (auto-knee-gap . 7) + (auto-knee-gap . 5.5) (font-name . "cmr10") (space-function . ,Beam::space_function) (meta . ((interfaces . (staff-symbol-referencer-interface beam-interface spanner-interface)))) @@ -441,7 +441,8 @@ (LyricText . ( (molecule-callback . ,Text_item::brew_molecule) - (X-offset-callbacks . (,Self_alignment_interface::aligned_on_self)) + (X-offset-callbacks . (,Self_alignment_interface::centered_on_parent + ,Self_alignment_interface::aligned_on_self)) (self-alignment-X . 0) (word-space . 0.6) (ignore-length-mismatch . #f) @@ -449,6 +450,7 @@ (end-alignment . 2) (font-family . roman) (font-shape . upright) + ;; duh, side-position-interface? (meta . ((interfaces . (lyric-syllable-interface self-alignment-interface text-interface font-interface item-interface )))) )) diff --git a/scm/grob-property-description.scm b/scm/grob-property-description.scm index 84c3eae75d..52cb8bf0be 100644 --- a/scm/grob-property-description.scm +++ b/scm/grob-property-description.scm @@ -85,7 +85,8 @@ these symbols may be alongside-stem, stem, head or loose-end.") attachments to prevent ugly slurs. [fixme: we need more documentation here]. .") (grob-property-description 'auto-properties boolean? "if true, as many properties of this grob as possible will be determined automatically from the musical context.") -(grob-property-description 'auto-knee-gap number-or-boolean? "the minimal smallest gap between two adjacent beamed chords for which beam will create auto-knees. Set to false for no auto knees." ) +(grob-property-description 'auto-knee-gap number? "If a gap is found between noteheads +where a horizontal beam fits that is larger than this number, make a kneed beam.") (grob-property-description 'axes list? "list of axis numbers. In the case of alignment grobs, this should contain only one number.") (grob-property-description 'bar-size number? "size of a bar line.") diff --git a/stepmake/stepmake/generic-targets.make b/stepmake/stepmake/generic-targets.make index b6e588fd6e..f8517812e9 100644 --- a/stepmake/stepmake/generic-targets.make +++ b/stepmake/stepmake/generic-targets.make @@ -112,8 +112,11 @@ local-maintainerclean: install-strip: $(MAKE) INSTALL="$(INSTALL) -s" install +final-install: + install: local-install $(LOOP) + $(MAKE) final-install local-install: -- 2.39.5