]> git.donarmstrong.com Git - lilypond.git/commitdiff
patch::: 1.3.127.jcn2
authorJan Nieuwenhuizen <janneke@gnu.org>
Thu, 1 Feb 2001 15:17:13 +0000 (16:17 +0100)
committerJan Nieuwenhuizen <janneke@gnu.org>
Thu, 1 Feb 2001 15:17:13 +0000 (16:17 +0100)
1.3.127.jcn2
============

* Beam (y, dy) calculations now as list of scm functions.

* Added cleaned-up excerpt from Coriolan for tutorial.

* Bugfix: beam looks at smallest gap for auto knees.

* Property-description-fix: allow auto-knee-gap to be set to false.

12 files changed:
CHANGES
Documentation/user/refman.itely
VERSION
input/bugs/beamed-chord.ly [new file with mode: 0644]
input/tutorial/orchestral-score.ly [new file with mode: 0644]
lily/beam.cc
lily/include/beam.hh
lily/stem-tremolo.cc
scm/c++.scm
scm/grob-description.scm
scm/grob-property-description.scm
scm/translator-property-description.scm

diff --git a/CHANGES b/CHANGES
index 2af4125e728d4a3968e95e916825519e4c06d75e..0d4c60ba31c25625f087a6dbde9fd547d920343d 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,14 @@
+1.3.127.jcn2
+============
+
+* Beam (y, dy) calculations now as list of scm functions.
+
+* Added cleaned-up excerpt from Coriolan for tutorial.
+
+* Bugfix: beam looks at smallest gap for auto knees.
+
+* Property-description-fix: allow auto-knee-gap to be set to false.
+
 1.3.127.jcn1
 ============
 
index 1c85434ee252af5f659279ad25774fbd1ae051fe..57a51016beccc4a563202214f57c9550cbe4de47 100644 (file)
@@ -5,6 +5,21 @@
 @c to automagically fill in these menus
 @c before saving changes
 
+
+@ignore
+ TODO:
+
+   fix all FIXMEs
+
+   Rhythm staff (clef, x-notehead)
+   Piano pedals
+   \addlyrics, \autochange, \partcombine: music (re)grouping
+   markup text
+   postscript, scheme output?
+   (links to?) using/existance of ly2dvi, lilypond-book
+@end ignore
+
+
 @c.{Reference Manual}
 
 @node Reference Manual
@@ -1002,10 +1017,12 @@ See the documentation of @code{measurePosition}.
 * Ottava::                      
 * Span requests::               
 @end menu
+
 @c.   {Beam}
 @node Beam
 @subsubsection Beam
 @cindex Beam
+
 @c.    {Automatic beams}
 @unnumberedsubsubsec Automatic beams
 
@@ -1014,10 +1031,12 @@ See the documentation of @code{measurePosition}.
 
 @cindex @code{Voice.noAutoBeaming}
 
-By default, LilyPond will generate beams automatically.  This feature
-can be disabled by setting the @code{Voice.noAutoBeaming} property to
-true.  It can be overridden for specific cases by specifying explicit
-beams.
+LilyPond will group flagged notes and generate beams autmatically, where
+appropriate.  This feature can be disabled by setting the
+@code{Voice.noAutoBeaming} property to true, which you may find
+necessary for the melody that goes with lyrics, eg.  Automatic beaming
+can easily be overridden for specific cases by specifying explicit
+beams, see @ref{Manual beams}.
 
 @cindex @code{Voice.autoBeamSettings}
 @cindex @code{(end * * * *)}
@@ -1027,15 +1046,11 @@ A large number of Voice properties are used to decide how to generate
 beams.  Their default values appear in @file{scm/auto-beam.scm}.  In
 general, beams can begin anywhere, but their ending location is
 significant.  Beams can end on a beat, or at durations specified by the
-properties in
-@code{Voice.autoBeamSettings}.
-To end beams every quarter note, for example, you could set the property
-@code{(end * * * *)}  to @code{(make-moment 1
-4)}.  To end beams at every three eighth notes you would set
-it to @code{(make-moment 1 8)}.
-The same syntax can be used to specify beam
-starting points using
-@code{(begin * * * *)}, eg:
+properties in @code{Voice.autoBeamSettings}.  To end beams every quarter
+note, for example, you could set the property @code{(end * * * *)} to
+@code{(make-moment 1 4)}.  To end beams at every three eighth notes you
+would set it to @code{(make-moment 1 8)}.  The same syntax can be used
+to specify beam starting points using @code{(begin * * * *)}, eg:
 @quotation
 @example
 \property Voice.autoBeamSettings \override
@@ -1064,16 +1079,19 @@ you would use @code{(end * * 1 32)}.
 @c.    {Manual beams}
 @cindex Automatic beams
 @unnumberedsubsubsec Manual beams
-
 @cindex beams, manual
 @cindex @code{]}
 @cindex @code{[}
 
-FIXME
-Beaming can be generated automatically; see section @ref{Automatic Beaming}.
+For most situations, beaming can be generated automatically; see section
+@ref{Automatic Beaming}.  In certain cases it may be necessary to
+override the automatic beaming decisions that LilyPond makes.  You can
+do this by specifying beams explicitely.
 
-A beam is specified by surrounding the beamed notes with brackets
-`@code{[}' and `@code{]}'.  
+A manual beam is specified by surrounding the notes that should make up
+the beam, with brackets `@code{[}' and `@code{]}'.
+
+FIXME: example.  (or tell: why would the auto-beamer fail here?)
 
 @lilypond[fragment,verbatim,center]
   [a'8 a'] [a'16 a' a' a']
@@ -1082,13 +1100,12 @@ A beam is specified by surrounding the beamed notes with brackets
 @end lilypond
 
 
-@cindex @code{-}@code{-}
-
 
 @c.    {Adjusting beams}
 @unnumberedsubsubsec Adjusting beams
 @cindex Adjusting beams
 
+FIXME
 
 @c.   {Slur}
 
diff --git a/VERSION b/VERSION
index dbd42b45bb8aec0b91c3df6ff1bfb4a8d08ce3f8..4606ef3a639a9baebfefe99f702173902dd6c28f 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -2,7 +2,7 @@ PACKAGE_NAME=LilyPond
 MAJOR_VERSION=1
 MINOR_VERSION=3
 PATCH_LEVEL=127
-MY_PATCH_LEVEL=jcn1
+MY_PATCH_LEVEL=jcn2
 
 # use the above to send patches: MY_PATCH_LEVEL is always empty for a
 # released version.
diff --git a/input/bugs/beamed-chord.ly b/input/bugs/beamed-chord.ly
new file mode 100644 (file)
index 0000000..c274b48
--- /dev/null
@@ -0,0 +1,12 @@
+\header{
+texidoc="Beam thinks that first two notes should be stem down.  Can be fixed by uncommenting \stemUp";
+}
+
+\score{
+  \notes\relative c'{
+    %\stemUp
+    \clef alto;
+    \time 3/4;
+    r8 <d ( bes > ) bes' d <e-> g, c, c,> r |
+  }
+}
diff --git a/input/tutorial/orchestral-score.ly b/input/tutorial/orchestral-score.ly
new file mode 100644 (file)
index 0000000..2e641fb
--- /dev/null
@@ -0,0 +1,240 @@
+\version "1.3.120";
+
+\include "paper16.ly";
+
+% #(set! point-and-click #t)
+#(define text-flat '((font-relative-size . -2) (music "accidentals--1")))
+
+
+% Coriolan 218-222
+flautoI = \notes\relative c'' {
+  \property Score.currentBarNumber = #218
+  des2.()c4|e(f e)f|\break
+  r2 des4\sf()c|r2 des4\sf()c|
+}
+flautoII = \notes\relative c'' {
+ g2.()as4|bes(as bes)as|
+ R1*2
+}
+oboeI = \notes\relative c'' {
+ e2.()f4|e(f e)f|
+ r2 as|r as\sf|
+}
+oboeII = \notes\relative c'' {
+ g2.()as4|bes(as bes)as|
+ r2 as'|r as\sf|
+}
+clarinettoI = \notes\relative c' {
+  es2.()d4|c(bis c)bes|
+% r2 es4\sf()d|r2 es4\sf()d|
+}
+clarinettoII = \notes\relative c' {
+  es2.()d4|c(bes c)bes|
+% r2 es'4\sf()d|r2 es4\sf()d|
+}
+fagottoI = \notes\relative c' {
+  bes2.()as4|g(f g)f|
+  r r8 des' des4\sf()es|r r8 des des4\sf()es|
+}
+fagottoII = \notes\relative c' {
+  bes2.()as4 | g(f g)f|
+  f4 r r2 | f4 r r2|
+}
+cornoI = \notes\relative c''' {
+  g2. f4|g f g f|
+% r4 r8 f f2|r4 r8 f f2|
+}
+cornoII = \notes\relative c''' {
+  g,2. d'4|g, d' g, d'|
+  r4 r8 d d4\sf()es|r4 r8 d d4\sf()es|
+}
+tromboI = \notes\relative c'' {
+  c2. c4|c c c c|
+  R1*2|
+}
+tromboII = \notes\relative c' {
+  c2. c4|c c c c|
+  R1*2|
+}
+timpani = \notes\relative c {
+  c2:16 c4 c|c c c c |
+  R1*2|
+}
+violinoI = \notes\relative c' {
+ des'2:16\ff des4: c:|e,: f: e: f:|
+ r8 as des,4\sf~des()c |r8 as' des,4\sf~des()c|
+}
+violinoII = \notes\relative c' {
+  des2:16\ff des4: c: |  bes: as: bes: as:|
+% r8 as des,4\sf ~ des()c| r8 as' des,4\sf ~ des()c|
+}
+violaI = \notes\relative c' {
+  e2:16\ff e4: f:|b,: c: b: c:|
+  r4 r8 as as2\sf|r4 r8 as as2\sf|
+}
+violaII = \notes\relative c' {
+  bes2:16\ff bes4: as:|g: f: g: f: |
+  r4 r8 f f4\sf()ges|r4 r8 f f4\sf()ges|
+}
+violoncello = \notes\relative c {
+  bes2.\ff()as4|g( f g )f |
+  r4 r8 f' f4\sf()ges |r4 r8 f f4\sf()ges |
+}
+contrabasso = \notes\relative c {
+  bes2.\ff()as4|g( f g )f|
+  f4 r r2 |f'4 r r2|
+}
+
+
+
+%%
+%% Hmm, can't we move this to a `template.ly'
+%%
+\score {
+  < 
+    \context StaffGroup = wood <
+      \context Staff = flauti <
+       \property Staff.midiInstrument = #"flute"
+       \property Staff.instrument = "2 Flauti"
+       \property Staff.instr = "Fl."
+       \context Voice=one \partcombine Voice
+         \context Thread=one \flautoI
+         \context Thread=two \flautoII
+      >
+      \context Staff = oboes <
+       \property Staff.midiInstrument = #"oboe"
+       \property Staff.instrument = "2 Oboi"
+       \property Staff.instr = "Ob."
+       \context Voice=one \partcombine Voice
+         \context Thread=one \oboeI
+         \context Thread=two \oboeII
+      >
+      \context Staff = clarinets <
+        \property Staff.midiInstrument = #"clarinet"
+       \property Staff.instrument = #`((kern . 0.5)
+         (lines "2 Clarinetti" (rows "(B" ,text-flat ")")))
+       \property Staff.instr = #`((kern . 0.5)
+         (lines "Cl."  (rows "(B" ,text-flat ")")))
+       \property Staff.transposing = #-2
+       \notes \key f \major;
+       \context Voice=one \partcombine Voice
+         \context Thread=one \clarinettoI
+         \context Thread=two \clarinettoII
+      >
+      \context Staff = bassoons <
+       \property Staff.midiInstrument = #"bassoon"
+       \property Staff.instrument = "2 Fagotti"
+       \property Staff.instr = "Fg."
+       \clef bass;
+       \context Voice=one \partcombine Voice
+         \context Thread=one \fagottoI
+         \context Thread=two \fagottoII
+      >
+    >
+    \context StaffGroup = brass <
+      \context Staff = frenshHorns <
+        \property Staff.midiInstrument = #"french horn"
+       \property Staff.instrument = #`((kern . 0.5)
+         (lines "2 Corni" (rows "(E" ,text-flat ")")))
+       \property Staff.instr = #`((kern . 0.5)
+         (lines "Cor."  (rows "(E" ,text-flat ")")))
+       \property Staff.transposing = #3
+       \notes \key c \major;
+       \context Voice=one \partcombine Voice
+         \context Thread=one \cornoI
+         \context Thread=two \cornoII
+      >
+      \context Staff = trumpets <
+       \property Staff.midiInstrument = #"clarinet"
+       \property Staff.instrument = #`((kern . 0.5)
+         (lines "2 Trombe" (rows "(C)")))
+       \property Staff.instr = #`((kern . 0.5)
+         (lines "Tbe." (rows "(C)")))
+       \context Voice=one \partcombine Voice
+         \context Thread=one \tromboI
+         \context Thread=two \tromboII
+      >
+    >
+    \context StaffGroup = timpani <
+      \context Staff = timpani <
+       \property Staff.midiInstrument = #"timpani"
+       \property Staff.instrument = #'((kern . 0.5)
+         (lines "2 Timpani" "(C-G)"))
+       \property Staff.instr = #"Timp."
+       \clef bass;
+       \timpani
+      >
+    >
+    \context StaffGroup = strings <
+      \context GrandStaff = violins <
+       \context Staff = viI <
+         \property Staff.midiInstrument = #"violin"
+         \property Staff.instrument = "Violino I"
+         \property Staff.instr = "Vi. I"
+         \violinoI       
+       >
+       \context Staff = viII <
+         \property Staff.midiInstrument = #"violin"
+         \property Staff.instrument = "Violino II"
+         \property Staff.instr = "Vi. II"
+         \violinoII
+       >
+      >
+      \context Staff = vla <
+       \property Staff.midiInstrument = #"viola"
+       \property Staff.instrument = "Viola"
+       \property Staff.instr = "Vla."
+       \clef alto;
+       \context Voice=one \partcombine Voice
+         \context Thread=one \violaI
+         \context Thread=two \violaII
+      >
+      \context GrandStaff=bass <
+        \property GrandStaff.soloADue = ##t
+        \property GrandStaff.soloText = #""
+        \property GrandStaff.soloIIText = #""
+       % This is non-conventional, but currently it is
+       % the only way to tell the difference.
+        \property GrandStaff.aDueText = #"\\`a2"
+        \property GrandStaff.splitInterval = #'(1 . 0)
+        \property GrandStaff.changeMoment =
+         #`(,(make-moment 1 1) . ,(make-moment 1 1))
+
+        \context Staff=one <
+         \property Staff.midiInstrument = #"cello"
+         \property Staff.instrument = #'((kern . 0.5)
+           (lines "Violoncello" (rows "    e") (rows "Contrabasso")))
+         \property Staff.instr = "Vc."
+         \clef bass;
+       >
+       \context Staff=two <
+         \property Staff.midiInstrument = #"contrabass"
+         \property Staff.instrument = "Contrabasso"
+         \property Staff.instr = "C.B."
+         \clef bass;
+         \skip 1*4; % sustain clef
+       >
+       \context Staff=one \partcombine Staff
+         \context Voice=one \violoncello
+         \context Voice=two \contrabasso
+      >
+    >
+  >
+  \paper {
+    \paperSixteen
+    linewidth = 80 * \staffspace;
+    textheight = 200 * \staffspace;
+    \translator {
+      \OrchestralScoreContext
+      skipBars = ##t
+      % Hmm
+      currentBarNumber = #218
+      BarNumber \override #'padding = #3
+      RestCollision \override #'maximum-rest-count = #1
+      marginScriptHorizontalAlignment = #1
+      TimeSignature \override #'style = #'C
+    }
+    \translator { \HaraKiriStaffContext }
+  }
+}
+
index 8ac599334a73c9bf6e8a2a9f0e55bcc4f486c46e..f7c2f126ebfe88643961837a5c8af422a272fc29 100644 (file)
 
 /*
   [TODO]
+
+  * remove *-hs variables, and do all y-position stuff in staff-space.
+    This is not trivial, as Stem, and Stem_info both use point dimensions
+    (indicated by _f suffix) in several places too.
+
   * shorter! (now +- 1000 lines)
-    * less hairy code
-    * move paper vars to scm
+  * less hairy code
+  * move paper vars to scm
 
-  remove *-hs variables, and do all y-position stuff in staff-space.
-*/
+  */
 
 
 #include <math.h> // tanh.
@@ -202,7 +206,7 @@ Beam::consider_auto_knees (Grob *me)
          
          Real left = Stem::extremal_heads (stems[l])[d]
            ->relative_coordinate (common, Y_AXIS);
-         Real right = Stem::extremal_heads (stems[i])[d]
+         Real right = Stem::extremal_heads (stems[i])[-d]
            ->relative_coordinate (common, Y_AXIS);
 
          Real dy = right - left;
@@ -277,141 +281,104 @@ Beam::set_stem_shorten (Grob*m)
 }
 
 /*
-  Set elt properties height and y-position if not set.
-  Adjust stem lengths to reach beam.
+  Call list of y-dy-callbacks, that handle setting of
+  grob-properties y, dy.
+
+  User may set grob-properties: y-position-hs and height-hs
+  (to be fixed) that override the calculated y and dy.
+
+  Because y and dy cannot be calculated and quanted separately, we
+  always calculate both, then check for user override.
  */
-MAKE_SCHEME_CALLBACK(Beam,after_line_breaking,1);
+MAKE_SCHEME_CALLBACK (Beam, after_line_breaking, 1);
 SCM
 Beam::after_line_breaking (SCM smob)
 {
   Grob * me =  unsmob_grob (smob);
-
-  /* first, calculate y, dy */
-  Real y, dy;
-  calc_default_position_and_height (me, &y, &dy);
-  if (visible_stem_count (me))
-    {
-      if (suspect_slope_b (me, y, dy))
-       dy = 0;
-
-      Real damped_dy = calc_slope_damping_f (me, dy);
-      Real quantised_dy = quantise_dy_f (me, damped_dy);
-
-      y += (dy - quantised_dy) / 2;
-      dy = quantised_dy;
-    }
-  /*
-    until here, we used only stem_info, which acts as if dir=up
-   */
-  y *= Directional_element_interface::get (me);
-  dy *= Directional_element_interface::get (me);
-
-
-  Real half_space = Staff_symbol_referencer::staff_space (me) / 2;
-
-  /* weird: why do we do calc_position_and_height () ? regardless of
-     this setting?
-
-     If the user sets height, we still need to calculate the y-position.
-     If the user sets height-hs, we still need to calculate and
-     quantise y-position.
-
-     We use least squares to calculate y-position and height, so we
-     inherently always calculate both.  */
   
-  /* check for user-override of dy */
-  SCM s = me->remove_grob_property ("height-hs");
-  if (gh_number_p (s))
-    {
-      dy = gh_scm2double (s) * half_space;
-    }
-  me->set_grob_property ("height", gh_double2scm (dy));
+  me->set_grob_property ("y", gh_double2scm (0));
+  me->set_grob_property ("dy", gh_double2scm (0));
 
-  /* check for user-override of y */
-  s = me->remove_grob_property ("y-position-hs");
-  if (gh_number_p (s))
-    {
-      y = gh_scm2double (s) * half_space;
-    }
-  else
-    { 
-      /* we can modify y, so we should quantise y */
-      Real y_shift = check_stem_length_f (me, y, dy);
-      y += y_shift;
-      y = quantise_y_f (me,y, dy, 0);
-      set_stem_length (me, y, dy);
-      y_shift = check_stem_length_f (me, y, dy);
+  /* Hmm, callbacks should be called by, a eh, callback mechanism
+    somewhere(?), I guess, not by looping here. */
+  
+  SCM list = me->get_grob_property ("y-dy-callbacks");
+  for (SCM i = list; gh_pair_p (i); i = gh_cdr (i))
+    gh_call1 (gh_car (i), smob);
 
-      if (y_shift > half_space / 4)
-       {
-         y += y_shift;
-
-         /*
-           for significantly lengthened or shortened stems,
-           request quanting the other way.
-         */
-         int quant_dir = 0;
-         if (abs (y_shift) > half_space / 2)
-           quant_dir = sign (y_shift) * Directional_element_interface::get (me);
-         y = quantise_y_f (me, y, dy, quant_dir);
-       }
-    }
   // UGH. Y is not in staff position unit?
   // Ik dacht datwe daar juist van weg wilden?
-  set_stem_length (me, y, dy);
-  me->set_grob_property ("y-position", gh_double2scm (y));
+  
+  // Hmm, nu hebben we 3 dimensies, want inmiddels zijn we daar
+  // weer terug, maar dan / 2
+  // (staff-space iso staff-position)
+  
+  set_stem_lengths (me);
 
   return SCM_UNSPECIFIED;
 }
 
-/*
-  See Documentation/tex/fonts.doc
- */
-void
-Beam::calc_default_position_and_height (Grob*me,Real* y, Real* dy) 
+
+MAKE_SCHEME_CALLBACK (Beam, least_squares, 1);
+SCM
+Beam::least_squares (SCM smob)
 {
-  *y = 0;
-  *dy = 0;  
-  if (visible_stem_count (me) <= 1)
-    return;
+ Grob *me = unsmob_grob (smob);
+
+ if (visible_stem_count (me) <= 1)
+   return SCM_UNSPECIFIED;
+
+  Real y = 0;
+  Real dy = 0;
 
   Real first_ideal = Stem::calc_stem_info (first_visible_stem (me)).idealy_f_;
   if (first_ideal == Stem::calc_stem_info (last_visible_stem (me)).idealy_f_)
     {
-      *dy = 0;
-      *y = first_ideal;
-      return;
+      y = first_ideal;
+      dy = 0;
     }
+  else
+    {
+      Array<Offset> ideals;
 
-  Array<Offset> ideals;
+      // ugh -> use commonx
+      Real x0 = first_visible_stem (me)->relative_coordinate (0, X_AXIS);
+      Link_array<Item> stems=
+       Pointer_group_interface__extract_elements (me, (Item*)0, "stems");
 
-  // ugh -> use commonx
-  Real x0 = first_visible_stem (me)->relative_coordinate (0, X_AXIS);
-  Link_array<Item> stems=
-    Pointer_group_interface__extract_elements (me, (Item*)0, "stems");
+      for (int i=0; i < stems.size (); i++)
+       {
+         Item* s = stems[i];
+         if (Stem::invisible_b (s))
+           continue;
+         ideals.push (Offset (s->relative_coordinate (0, X_AXIS) - x0, 
+                              Stem::calc_stem_info (s).idealy_f_));
+       }
+      Real dydx;
+      minimise_least_squares (&dydx, &y, ideals);
 
-  for (int i=0; i < stems.size (); i++)
-    {
-      Item* s = stems[i];
-      if (Stem::invisible_b (s))
-        continue;
-      ideals.push (Offset (s->relative_coordinate (0, X_AXIS) - x0, 
-                          Stem::calc_stem_info (s).idealy_f_));
+      Real dx = last_visible_stem (me)->relative_coordinate (0, X_AXIS) - x0;
+      dy = dydx * dx;
     }
-  Real dydx;
-  minimise_least_squares (&dydx, y, ideals); // duh, takes references
 
-  Real dx = last_visible_stem (me)->relative_coordinate (0, X_AXIS) - x0;
-  *dy = dydx * dx;
+  me->set_grob_property ("y", gh_double2scm (y));
+  me->set_grob_property ("dy", gh_double2scm (dy));
+  return SCM_UNSPECIFIED;
 }
 
-bool
-Beam::suspect_slope_b (Grob*me, Real y, Real dy) 
+MAKE_SCHEME_CALLBACK (Beam, cancel_suspect_slope, 1);
+SCM
+Beam::cancel_suspect_slope (SCM smob)
 {
-  /* first, calculate y, dy */
-  /*
-    steep slope running against lengthened stem is suspect
-  */
+  Grob *me = unsmob_grob (smob);
+  
+  if (visible_stem_count (me) <= 1)
+    return SCM_UNSPECIFIED;
+  
+  Real y = gh_scm2double (me->get_grob_property ("y"));
+  Real dy = gh_scm2double (me->get_grob_property ("dy"));
+
+ /* steep slope running against lengthened stem is suspect */
   Real first_ideal = Stem::calc_stem_info (first_visible_stem (me)).idealy_f_;
   Real last_ideal = Stem::calc_stem_info (last_visible_stem (me)).idealy_f_;
   Real lengthened = gh_scm2double (me->get_grob_property ("outer-stem-length-limit"));
@@ -424,9 +391,11 @@ Beam::suspect_slope_b (Grob*me, Real y, Real dy)
   if (((y - first_ideal > lengthened) && (dydx > steep))
       || ((y + dy - last_ideal > lengthened) && (dydx < -steep)))
     {
-      return true;
+      Real adjusted_y = y + dy / 2;
+      me->set_grob_property ("y", gh_double2scm (adjusted_y));
+      me->set_grob_property ("dy", gh_double2scm (0)); 
     }
-  return false;
+  return SCM_UNSPECIFIED;
 }
 
 /*
@@ -434,24 +403,184 @@ Beam::suspect_slope_b (Grob*me, Real y, Real dy)
   damped = tanh (slope)
   corresponds with some tables in [Wanske]
 */
-Real
-Beam::calc_slope_damping_f (Grob*me,Real dy) 
+MAKE_SCHEME_CALLBACK (Beam, slope_damping, 1);
+SCM
+Beam::slope_damping (SCM smob)
 {
-  SCM damp = me->get_grob_property ("damping"); 
-  int damping = gh_scm2int (damp);
+  Grob *me = unsmob_grob (smob);
+
+  if (visible_stem_count (me) <= 1)
+    return SCM_UNSPECIFIED;
+
+  SCM s = me->get_grob_property ("damping"); 
+  int damping = gh_scm2int (s);
 
   if (damping)
     {
-  // ugh -> use commonx
+      Real y = gh_scm2double (me->get_grob_property ("y"));
+      Real dy = gh_scm2double (me->get_grob_property ("dy"));
+      
+      // ugh -> use commonx
       Real dx = last_visible_stem (me)->relative_coordinate (0, X_AXIS)
        - first_visible_stem (me)->relative_coordinate (0, X_AXIS);
       Real dydx = dy && dx ? dy/dx : 0;
       dydx = 0.6 * tanh (dydx) / damping;
-      return dydx * dx;
+
+      Real damped_dy = dydx * dx;
+      Real adjusted_y = y + (dy - damped_dy) / 2;
+      me->set_grob_property ("y", gh_double2scm (adjusted_y));
+      me->set_grob_property ("dy", gh_double2scm (damped_dy));
     }
-  return dy;
+    return SCM_UNSPECIFIED;
 }
 
+/*
+  Quantise dy (height) of beam.
+  Generalisation of [Ross].
+  */
+MAKE_SCHEME_CALLBACK (Beam, quantise_dy, 1);
+SCM
+Beam::quantise_dy (SCM smob)
+{
+  Grob *me = unsmob_grob (smob);
+
+  if (visible_stem_count (me) <= 1)
+    return SCM_UNSPECIFIED;
+
+  Array<Real> a;
+  SCM proc = me->get_grob_property ("height-quants");
+  SCM quants = gh_call2 (proc, me->self_scm (),
+                        gh_double2scm (me->paper_l ()->get_var ("stafflinethickness")
+                                       / 1.0));
+  
+  for (SCM s = quants; gh_pair_p (s); s = gh_cdr (s))
+    a.push (gh_scm2double (gh_car (s)));
+  
+  if (a.size () > 1)
+    {
+      Real y = gh_scm2double (me->get_grob_property ("y"));
+      Real dy = gh_scm2double (me->get_grob_property ("dy"));
+
+      Real staff_space = Staff_symbol_referencer::staff_space (me);
+      
+      Interval iv = quantise_iv (a, abs (dy)/staff_space) * staff_space;
+      Real q = (abs (dy) - iv[SMALLER] <= iv[BIGGER] - abs (dy))
+       ? iv[SMALLER]
+       : iv[BIGGER];
+      
+      Real quantised_dy = q * sign (dy);
+      Real adjusted_y = y + (dy - quantised_dy) / 2;
+      me->set_grob_property ("y", gh_double2scm (adjusted_y));
+      me->set_grob_property ("dy", gh_double2scm (quantised_dy));
+    }
+  return SCM_UNSPECIFIED;
+}
+
+
+/*
+  What to do?  Why do we have two dimensions (staff-position and
+  staff-space)?  Do other grobs export staff-position to the user,
+  should we junk that?
+  
+  height-hs -> staff-position-height
+  y-position-hs -> staff-position
+
+  or
+
+  height-hs -> height / 2
+  y-postion-hs -> y-position / 2
+
+  
+  UGHUGH.  IF this callback is omitted, we hang.
+  FIXME: until here, we used only stem_info, which acts as if dir=up.
+*/
+MAKE_SCHEME_CALLBACK (Beam, user_override, 1);
+SCM
+Beam::user_override (SCM smob)
+{
+  Grob *me = unsmob_grob (smob);
+  Real half_space = Staff_symbol_referencer::staff_space (me) / 2;
+
+  Real y = gh_scm2double (me->get_grob_property ("y"));
+  Real dy = gh_scm2double (me->get_grob_property ("dy"));
+
+  
+  SCM s = me->get_grob_property ("y-position-hs");
+  if (gh_number_p (s))
+    y = gh_scm2double (s) * half_space;
+  else
+    // ughugh
+    y *= Directional_element_interface::get (me);
+
+  s = me->get_grob_property ("height-hs");
+  if (gh_number_p (s))
+    dy = gh_scm2double (s) * half_space;
+  else
+    // ughugh
+    dy *= Directional_element_interface::get (me);
+
+  
+  me->set_grob_property ("y", gh_double2scm (y));
+  me->set_grob_property ("dy", gh_double2scm (dy));
+  
+  return SCM_UNSPECIFIED;
+}
+
+/*
+  Ugh, this must be last, after user_override
+  Assumes directionised y/dy.
+ */
+MAKE_SCHEME_CALLBACK (Beam, do_quantise_y, 1);
+SCM
+Beam::do_quantise_y (SCM smob)
+{
+  Grob *me = unsmob_grob (smob);
+
+  /*
+    If the user set y-position, we shouldn't do quanting.
+   */
+  if (gh_number_p (me->get_grob_property ("y-position-hs")))
+    return SCM_UNSPECIFIED;
+
+  Real y = gh_scm2double (me->get_grob_property ("y"));
+  Real dy = gh_scm2double (me->get_grob_property ("dy"));
+      
+  /* we can modify y, so we should quantise y */
+  Real half_space = Staff_symbol_referencer::staff_space (me) / 2;
+  Real y_shift = check_stem_length_f (me, y, dy);
+  y += y_shift;
+  y = quantise_y_f (me, y, dy, 0);
+
+  /*
+    Hmm, this is a bit keyhole operation: we're passing `this' as a
+    parameter, and member vars as SCM properties.  We should decide on
+    SCM/C/C++ boundary */
+  me->set_grob_property ("y", gh_double2scm (y));
+  set_stem_lengths (me);
+  y = gh_scm2double (me->get_grob_property ("y"));
+  
+  y_shift = check_stem_length_f (me, y, dy);
+
+  if (y_shift > half_space / 4)
+    {
+      y += y_shift;
+
+      /*
+       for significantly lengthened or shortened stems,
+       request quanting the other way.
+      */
+      int quant_dir = 0;
+      if (abs (y_shift) > half_space / 2)
+       quant_dir = sign (y_shift) * Directional_element_interface::get (me);
+      y = quantise_y_f (me, y, dy, quant_dir);
+    }
+  
+  me->set_grob_property ("y", gh_double2scm (y));
+  // me->set_grob_property ("dy", gh_double2scm (dy));
+  return SCM_UNSPECIFIED;
+}
+
+
 Real
 Beam::calc_stem_y_f (Grob*me,Item* s, Real y, Real dy) 
 {
@@ -530,15 +659,18 @@ Beam::check_stem_length_f (Grob*me,Real y, Real dy)
   stem directions and length should set to relative to the chord's
   position of the beam.  */
 void
-Beam::set_stem_length (Grob*me,Real y, Real dy)
+Beam::set_stem_lengths (Grob *me)
 {
+  if (visible_stem_count (me) <= 1)
+    return;
+  
+  Real y = gh_scm2double (me->get_grob_property ("y"));
+  Real dy = gh_scm2double (me->get_grob_property ("dy"));
+
   Real half_space = Staff_symbol_referencer::staff_space (me)/2;
   Link_array<Item> stems=
     Pointer_group_interface__extract_elements (me, (Item*)0, "stems");
 
-  if (stems.size () < 1)
-    return;
-  
   Grob *common = me->common_refpoint (stems[0], Y_AXIS);
   for (int i=1; i < stems.size (); i++)
     if (!Stem::invisible_b (stems[i]))
@@ -559,46 +691,10 @@ Beam::set_stem_length (Grob*me,Real y, Real dy)
     }
 }
 
-/*
-  [Ross] (simplification of)
-  Set dy complying with:
-    - zero
-    - thick / 2 + staffline_f / 2
-    - thick + staffline_f
-  + n * staff_space
-*/
-Real
-Beam::quantise_dy_f (Grob*me,Real dy) 
-{
-  Array<Real> a;
-
-  SCM proc = me->get_grob_property ("height-quants");
-  SCM quants = gh_call2 (proc, me->self_scm (),
-                        gh_double2scm (me->paper_l ()->get_var ("stafflinethickness")
-                                       / 1.0));
-  
-  
-  for (SCM s = quants; gh_pair_p (s); s = gh_cdr (s))
-    a.push (gh_scm2double (gh_car (s)));
-  
-  if (a.size () <= 1)
-    return dy;
-
-  Real staff_space = Staff_symbol_referencer::staff_space (me);
-  
-  Interval iv = quantise_iv (a, abs (dy)/staff_space) * staff_space;
-  Real q = (abs (dy) - iv[SMALLER] <= iv[BIGGER] - abs (dy))
-    ? iv[SMALLER]
-    : iv[BIGGER];
-  
-  return q * sign (dy);
-}
-
 /*
   Prevent interference from stafflines and beams.
-  See Documentation/tex/fonts.doc
 
-  We only need to quantise the (left) y-position of the beam,
+  We only need to quantise the (left) y of the beam,
   since dy is quantised too.
   if extend_b then stems must *not* get shorter
  */
@@ -694,7 +790,7 @@ Beam::stem_beams (Grob*me,Item *here, Item *next, Item *prev)
   Real dx = visible_stem_count (me) ?
     last_visible_stem (me)->relative_coordinate (0, X_AXIS) - first_visible_stem (me)->relative_coordinate (0, X_AXIS)
     : 0.0;
-  Real dy = gh_scm2double (me->get_grob_property ("height"));
+  Real dy = gh_scm2double (me->get_grob_property ("dy"));
   Real dydx = dy && dx ? dy/dx : 0;
 
   Molecule leftbeams;
@@ -794,10 +890,6 @@ Beam::stem_beams (Grob*me,Item *here, Item *next, Item *prev)
   return leftbeams;
 }
 
-/*
-  TODO: it would be nice to introduce y-position via callbacks.
- */
-
 MAKE_SCHEME_CALLBACK(Beam,brew_molecule,1);
 SCM
 Beam::brew_molecule (SCM smob)
@@ -823,9 +915,9 @@ Beam::brew_molecule (SCM smob)
     }
   
   
-  Real dy = gh_scm2double (me->get_grob_property ("height"));
+  Real dy = gh_scm2double (me->get_grob_property ("dy"));
   Real dydx = dy && dx ? dy/dx : 0;
-  Real y = gh_scm2double (me->get_grob_property ("y-position"));
+  Real y = gh_scm2double (me->get_grob_property ("y"));
 
 
   for (int j=0; j <stems.size  (); j++)
@@ -945,11 +1037,11 @@ Beam::rest_collision_callback (SCM element_smob, SCM axis)
 
 
   // todo: make sure this calced already.
-  SCM s = beam->get_grob_property ("height");
+  SCM s = beam->get_grob_property ("dy");
   if (gh_number_p (s))
     beam_dy = gh_scm2double (s);
   
-  s = beam->get_grob_property ("y-position");
+  s = beam->get_grob_property ("y");
   if (gh_number_p (s))
     beam_y = gh_scm2double (s);
   
@@ -993,10 +1085,12 @@ Beam::has_interface (Grob*me)
 void
 Beam::set_interface (Grob*me)
 {
+#if 0
   /*
     why the init? No way to tell difference between default and user
     override.  */
-  me->set_grob_property ("height", gh_int2scm (0)); // ugh.
-  me->set_grob_property ("y-position" ,gh_int2scm (0));
+  me->set_grob_property ("y" ,gh_double2scm (0));
+  me->set_grob_property ("dy", gh_double2scm (0));
   me->set_interface (ly_symbol2scm("beam-interface"));
+#endif
 }
index 18126770aff1a6523ef5a2e89317a1f42ffe0223..c1eb843b1a261a9703600b7ef50d289bccc16ec0 100644 (file)
@@ -29,6 +29,17 @@ public:
   DECLARE_SCHEME_CALLBACK(brew_molecule, (SCM ));
   DECLARE_SCHEME_CALLBACK(before_line_breaking, (SCM ));
   DECLARE_SCHEME_CALLBACK(after_line_breaking, (SCM ));
+
+  /*
+    y-dy callbacks
+   */
+  DECLARE_SCHEME_CALLBACK (least_squares, (SCM));
+  DECLARE_SCHEME_CALLBACK (cancel_suspect_slope, (SCM));
+  DECLARE_SCHEME_CALLBACK (slope_damping, (SCM));
+  DECLARE_SCHEME_CALLBACK (quantise_dy, (SCM));
+  DECLARE_SCHEME_CALLBACK (user_override, (SCM));
+  DECLARE_SCHEME_CALLBACK (do_quantise_y, (SCM));
+
   static Molecule stem_beams (Grob*,Item *here, Item *next, Item *prev);
 
 private:
@@ -36,13 +47,9 @@ private:
   static void set_stem_directions (Grob*);
   static void consider_auto_knees (Grob*);
   static void set_stem_shorten (Grob*);
-  static void calc_default_position_and_height (Grob*,Real* y, Real* dy);
-  static bool suspect_slope_b (Grob*, Real y, Real dy);
-  static Real calc_slope_damping_f (Grob*, Real dy);
   static Real calc_stem_y_f (Grob*, Item* s, Real y, Real dy);
   static Real check_stem_length_f (Grob*, Real y, Real dy);
-  static void set_stem_length (Grob*, Real y, Real dy);
-  static Real quantise_dy_f (Grob*, Real dy);
+  static void set_stem_lengths (Grob*);
   static Real quantise_y_f (Grob*, Real y, Real dy, int quant_dir);
   static int forced_stem_count (Grob*);
 };
index 36cbc63f97f4cbb6eea3eeb1f3838b462ae101c7..5ff2b8f2a52ffff5e5d9ec0af16f8140bb14b01b 100644 (file)
@@ -76,7 +76,7 @@ Stem_tremolo::brew_molecule (SCM smob)
   if (beam)
     {
       Real dy = 0;
-      SCM s = beam->get_grob_property ("height");
+      SCM s = beam->get_grob_property ("dy");
       if (gh_number_p (s))
        dy = gh_scm2double (s);
       Real dx = Beam::last_visible_stem (beam)->relative_coordinate (0, X_AXIS)
index e3ce13b8754e764bb8f14c79cdb6a0ddc54765bf..18cd4e273f51be9eeaea128e4faea747ef950670 100644 (file)
@@ -8,14 +8,20 @@
 ;;; Note: this file can't be used without LilyPond executable
 
 (define (number-pair?  x)
-  (and (pair? x) (number? (car x)) (number? (cdr x))))
+  (and (pair? x)
+       (number? (car x)) (number? (cdr x))))
 
-(define (boolean-or-symbol? x) (or boolean? x) (or symbol? x))
+(define (boolean-or-symbol? x)
+  (or (boolean? x) (symbol? x)))
 
-(define (number-or-string? x) (or (number? x) (string? x)))
+(define (number-or-boolean? x)
+  (or (number? x) (boolean? x)))
 
-(define markup?
-  (lambda (x) (or (string? x) (list? x))))
+(define (number-or-string? x)
+  (or (number? x) (string? x)))
+
+(define (markup? x)
+  (or (string? x) (list? x)))
 
 ;; ugh: code dup ; merge.
 (define (object-type obj)
@@ -39,6 +45,7 @@
    ((procedure? obj) "procedure") 
    ((boolean-or-symbol? obj) "boolean or symbol")
    ((number-or-string? obj) "number or string")
+   ((number-or-boolean? obj) "number or boolean")
    ((markup? obj) "markup (list or string)")
    (else "unknown type")))
 
index 47ee15416f3cec19545277210cdcf70e99de0a06..df810a004842e80041588d9c184598205f2cdf70 100644 (file)
                 ;; todo: clean this up a bit: the list is getting
                 ;; rather long.
                 (molecule-callback . ,Beam::brew_molecule)
+                (y-dy-callbacks . (,Beam::least_squares
+                                   ,Beam::cancel_suspect_slope
+                                   ,Beam::slope_damping
+                                   ,Beam::quantise_dy
+                                   ,Beam::user_override
+                                   ,Beam::do_quantise_y))
+                                                        
                 (thickness . 0.48) ; in staff-space
                 (before-line-breaking-callback . ,Beam::before_line_breaking)
                 (after-line-breaking-callback . ,Beam::after_line_breaking)
index cc6de9985d8801f58dd49e8399856fa6c6db8aa9..8eb13e78ce5fa9e255d4913dbe78e043d0de19f8 100644 (file)
@@ -41,11 +41,8 @@ This procedure is called (using dependency resolution) after line breaking. Retu
 '(LEFT-offset . RIGHT-offset).  This offset is added to the
 attachments to prevent ugly slurs.  [fixme: we need more documentation here].
 .")
-(grob-property-description 'auto-interstaff-knee-gap number? ".")
-(grob-property-description 'auto-knee-gap number? ".")
-
+(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 '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.")
 (grob-property-description 'bars list? "list of barline pointers.")
index 7ee1dc69cbd898402539eaf0643406ac194170e7..b34dc23090e4fc6cd9d109af3f611039570adab6 100644 (file)
@@ -100,6 +100,7 @@ key signatures after the bar lines:
 @end example
 ")
 (translator-property-description 'centralCPosition number? "Place of the central C. Usually determined by looking at clefPosition and clefGlyph.")
+(translator-property-description 'changeMoment moment? "duration that voices are examined for differences, when part-combining.  Usually unset or zero when combining threads into one voice, and 1 (or the duration of one measure) when combining voices into one staff.")
 (translator-property-description 'chordChanges boolean? "Only show changes in chords scheme?")
 (translator-property-description 'clefGlyph string? "Name of the symbol within the music font")
 (translator-property-description 'clefOctavation integer? "Add
@@ -241,7 +242,8 @@ r1 r1*3 R1*3  \\\\property Score.skipBars= ##t r1*3 R1*3
 (translator-property-description 'soloIIText string? "text for begin of solo for voice ``two'' when part-combining.")
 (translator-property-description 'soloText string? "text for begin of solo when part-combining.")
 (translator-property-description 'sparseTies boolean? "only create one tie per chord.")
-(translator-property-description 'split-interval number-pair? "always split into two voices for contained intervals when part-combining.")
+(translator-property-description 'splitInterval number-pair? "part-combiner will separate its two voices (or threads) when interval between the two voices is contained in this range.")
+(translator-property-description 'split-interval boolean? "set if part-combiner separated voices based on splitInterval.")
 (translator-property-description 'squashedPosition integer? " Vertical position of
 squashing for Pitch_squash_engraver.")
 (translator-property-description 'staffsFound list? "list of all staff-symbols found.")