]> git.donarmstrong.com Git - lilypond.git/commitdiff
* lily/beam.cc (consider_auto_knees): rewrite function; now only
authorHan-Wen Nienhuys <hanwen@xs4all.nl>
Sat, 3 Aug 2002 00:43:19 +0000 (00:43 +0000)
committerHan-Wen Nienhuys <hanwen@xs4all.nl>
Sat, 3 Aug 2002 00:43:19 +0000 (00:43 +0000)
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.

22 files changed:
ChangeLog
Documentation/user/tutorial.itely
GNUmakefile.in
input/bugs/bizarre-beam.ly [deleted file]
input/bugs/divisi-staff.ly [deleted file]
input/bugs/knee.ly [deleted file]
input/bugs/lyrics-bar.ly [deleted file]
input/bugs/lyrics-spacing.ly [deleted file]
input/bugs/markup-definition.ly [deleted file]
input/bugs/rest-melisma.ly
input/bugs/slur-attachment.ly [deleted file]
input/bugs/slur-dx.ly [deleted file]
input/bugs/slur-steep-broken.ly [deleted file]
input/regression/auto-knee.ly
lily/beam.cc
lily/include/lyric-phrasing-engraver.hh
lily/lyric-phrasing-engraver.cc
lily/syllable-group.cc
scm/c++.scm
scm/grob-description.scm
scm/grob-property-description.scm
stepmake/stepmake/generic-targets.make

index 7cd2ccfb0c25ec75abc31d25ce156e313c6b5fe7..0571e8f02cf48621bc826948e4b6f5e8a515e209 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2002-08-03  Han-Wen  <hanwen@cs.uu.nl>
+
+       * 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  <hanwen@cs.uu.nl>
 
        * lily/beam.cc (connect_beams): fix quarter note beams.
index a8dc14a6a1d53c67cd5b9b7aa94afbfbb7e1302b..cdc4d0ef51c2f3f0e635eb6a780348656e780cc6 100644 (file)
@@ -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
index d3faf38932d91c7bd184a7b974b4c76edcff3ec4..16aa3d02ec980ce738a4f3e563b0698d209be179 100644 (file)
@@ -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 (file)
index b1abf20..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-\score{ \notes {g''4 [<e'''8 g> 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 (file)
index 1c5673d..0000000
+++ /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 (file)
index 02f3524..0000000
+++ /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 (file)
index 2170b9f..0000000
+++ /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 (file)
index cabb282..0000000
+++ /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 (file)
index ff2a616..0000000
+++ /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"))
-    
-  }}
index 762b782efe16e4026611ab81c7389a507d724ce1..5f53d423506b243020665235cee07bc7fe17b461 100644 (file)
@@ -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 (file)
index 8a21d68..0000000
+++ /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 (file)
index ed15d3b..0000000
+++ /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 (file)
index 78b6301..0000000
+++ /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
-  }
-}
-
index 6cfd2f50bd3e13267895cc9216930ad441454eb8..fc72a3d0096d145ff4a86e6111082fc7d09eb088 100644 (file)
@@ -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
-%    }
   }
 }
index 695a704750f135483c86fa085342dfee1e293164..43c7d7a9cab4e9a02fb123b92b7e03fcd2755ded 100644 (file)
@@ -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<Interval> 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 (Grobme, 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<Grob> 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<Interval> 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:
index d3a8339d2ab4d9eb51f33d4b9b5d006420461040..48ad83a32ec8fb31178aefca766181a41c9f8d75 100644 (file)
@@ -94,7 +94,7 @@ class Syllable_group
 {
   bool first_in_phrase_b_;
   Grob * notehead_;
-  Link_array<Grob> lyric_list_;
+  Link_array<Grob> 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);
index 483d85d2c4317d247a67ac292fba7703458ca72f..5db329f4793115ff21d08ee320e16a6461961887 100644 (file)
@@ -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",
index 1650fd94afd2805bf98cda3c288fbce1d5a5da63..909a296bde62f3ed70e7ca8196ba8ec228607c34 100644 (file)
@@ -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<Spanner*> (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<Spanner*> (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 <? translate;
-    }
+  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 <? translate;
+       }
     
-    translate *= alignment_ ;
-  }
+      translate *= alignment_ ;
+    }
   return translate;
 }
 
 
 /** determine what alignment we want.
     Rules: if property alignment is set it specifies the alignment
-           if first_in_phrase_b_ is set, then alignment is LEFT.
-           otherwise if each syllable ends in punctuation, then alignment is RIGHT
-          otherwise alignment is centre.
+    if first_in_phrase_b_ is set, then alignment is LEFT.
+    otherwise if each syllable ends in punctuation, then alignment is RIGHT
+    otherwise alignment is centre.
 */
 int 
 Syllable_group::appropriate_alignment (const char *punc)
 {
-
   SCM s=this->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");
 
index 58d6222636466317d4d880829aca0dfa9db47e5e..41bd34139e4243869fe608a20859336feafc449a 100644 (file)
@@ -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")
    ))
index cdc3f05145f7d1581a8fe40bcbba315d0bb44f32..3b9790090cd48ad9f276051dd0eba92a09c24f57 100644 (file)
        (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))))
     (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)
        (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 ))))
        ))
index 84c3eae75d1c5ae6b63045470b5fe36a69a74317..52cb8bf0be0a081ece0c025f2390555b7b68a735 100644 (file)
@@ -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.")
index b6e588fd6ef515f6b16bd6502ad0c2ce6a8e0ae6..f8517812e91bf5ce3553bdc90c8ec3a4c60afcb2 100644 (file)
@@ -112,8 +112,11 @@ local-maintainerclean:
 install-strip:
        $(MAKE) INSTALL="$(INSTALL) -s" install
 
+final-install:
+
 install: local-install
        $(LOOP)
+       $(MAKE) final-install
 
 local-install: