]> git.donarmstrong.com Git - lilypond.git/commitdiff
Merge branch 'master' of ssh+git://git.sv.gnu.org/srv/git/lilypond
authorWerner Lemberg <wl@gnu.org>
Wed, 18 Apr 2007 15:21:31 +0000 (17:21 +0200)
committerWerner Lemberg <wl@gnu.org>
Wed, 18 Apr 2007 15:21:31 +0000 (17:21 +0200)
37 files changed:
Documentation/user/running.itely
Documentation/user/spacing.itely
buildscripts/makelsr.py
input/lsr/connecting/beam-across-line-breaks.ly [new file with mode: 0644]
input/lsr/connecting/short-tremolos.ly [new file with mode: 0644]
input/lsr/contemporary/feathered-beams.ly [new file with mode: 0644]
input/lsr/spacing/alignment-order.ly [new file with mode: 0644]
input/lsr/spacing/alignment-vertical-spacing.ly
input/regression/arpeggio-span-one-staff.ly [new file with mode: 0644]
input/regression/beam-quanting-horizontal.ly
input/regression/chromatic-scales.ly [new file with mode: 0644]
input/regression/page-turn-page-breaking-auto-first-page2.ly
input/regression/page-turn-page-breaking-repeats.ly
input/regression/page-turn-page-breaking.ly
lily/align-interface.cc
lily/arpeggio.cc
lily/include/arpeggio.hh
lily/include/optimal-page-breaking.hh
lily/include/page-breaking.hh
lily/include/page-spacing.hh
lily/include/page-turn-page-breaking.hh
lily/main.cc
lily/note-heads-engraver.cc
lily/optimal-page-breaking.cc
lily/page-breaking.cc
lily/page-spacing.cc
lily/page-turn-page-breaking.cc
lily/paper-column-engraver.cc
lily/phrasing-slur-engraver.cc
lily/span-arpeggio-engraver.cc
lily/system.cc
lily/tab-note-heads-engraver.cc
ly/graphviz-init.ly
scm/define-context-properties.scm
scm/define-grobs.scm
scm/graphviz.scm
scm/lily.scm

index 0644f342205cbc878f03f7f367bf07feb97be852..dc7ac08f3dc30a6be5a29b30ae95b6f229fe0269 100644 (file)
@@ -727,6 +727,18 @@ instructions, visit @uref{http://lilypondtool@/.organum@/.hu}
 All these editors can be made to jump into the input file to the source
 of a symbol in the graphical output.  See @ref{Point and click}.
 
+In addition, several other text editors provide some support for
+LilyPond, including
+
+@table @asis
+@item TexShop
+The @uref{http://@/www@/.uoregon@/.edu/~koch/texshop/index@/.html,TexShop}
+editor for Mac OS X can be extended to run LilyPond, lilypond-book and
+convert-ly from within the editor, using the extensions available at 
+@uref{http://@/www@/.dimi@/.uniud@/.it/vitacolo/freesoftware@/.html}.
+
+@end table
+
 
 @node Point and click
 @section Point and click
index fbeb4c9dfd380360bdc87b5938ff4bb028089ede..95c42ffb7cb4981cd43ee5011b50ce744d60b156 100644 (file)
@@ -211,6 +211,13 @@ top-most of the next system. Default is@tie{}4mm.
 Increasing this will put systems whose bounding boxes almost touch
 farther apart.
 
+@funindex page-breaking-between-system-padding
+@item between-system-padding
+This variable tricks the page breaker into thinking that
+@code{between-system-padding} is set to something different than it
+really is. For example, if this variable is set to something substantially
+larger than @code{between-system-padding}, then the page-breaker will put
+fewer systems on each page.
 
 @funindex horizontal-shift
 @item horizontal-shift
@@ -600,13 +607,12 @@ This makes the following 28 measures (assuming 4/4 time) be broken every
 
 Internals: @internalsref{LineBreakEvent}.
 
-A linebreaking configuration can now be saved as a @code{.ly} file
+A linebreaking configuration can be saved as a @code{.ly} file
 automatically.  This allows vertical alignments to be stretched to
 fit pages in a second formatting run.  This is fairly new and
 complicated.  More details are available in
 @lsrdir{spacing}
 
-
 @refbugs
 
 Line breaks can only occur if there is a @q{proper} bar line.  A note
@@ -882,7 +888,7 @@ staves inside a system.
 * Vertical spacing inside a system::  
 * Vertical spacing between systems::  
 * Explicit staff and system positioning::  
-* Two-pass vertical spacing::   
+* Two-pass vertical spacing::
 * Vertical collision avoidance::  
 @end menu
 
@@ -922,6 +928,61 @@ first number is generally negative.  The numbers need not match;
 for example, the staff can be made larger at the bottom by setting
 it to @code{(-6 . 4)}.
 
+After page breaks are determined, the vertical spacing within each
+system is reevaluated in order to fill the page more evenly; if a page
+has space left over, systems are stretched in order to fill that space.
+The amount of stretching can be configured though the @code{max-stretch}
+property of the @internalsref{VerticalAlignment} grob. To disable this
+stretching entirely, set @code{max-stretch} to zero.
+
+In some situations, you may want to stretch most of a system while
+leaving some parts fixed. For example, if a piano part occurs in the
+middle of an orchestral score, you may want to leave the piano staves
+close to each other while stretching the rest of the score. The
+@code{keep-fixed-while-stretching} property of
+@internalsref{VerticalAxisGroup} can be used to achieve this. When set
+to @code{##t}, this property keeps its staff (or line of lyrics) from
+moving relative to the one directly above it. In the example above,
+you would override @code{keep-fixed-while-stretching} to @code{##t} in
+the second piano staff:
+
+@lilypond[verbatim]
+#(set-default-paper-size "a6")
+#(set-global-staff-size 14.0)
+
+\book {
+\paper {
+  ragged-last-bottom = ##f
+}
+
+\score {
+\new GrandStaff
+<<
+  \new StaffGroup
+  <<
+    \new Staff {c' d' e' f'}
+    \new Staff {c' d' e' f'}
+    \new Staff {c' d' e' f'}
+  >>
+
+  \new PianoStaff
+  <<
+    \new Staff {c' d' e' f'}
+    \new Staff \with {
+      \override VerticalAxisGroup #'keep-fixed-while-stretching = ##t
+    }
+    {c' d' e' f'}
+  >>
+
+  \new StaffGroup
+  <<
+    \new Staff {c' d' e' f'}
+    \new Staff {c' d' e' f'}
+  >>
+>>
+}
+}
+@end lilypond
 
 @seealso
 
@@ -1157,6 +1218,10 @@ passed to these different settings will avoid this.
 @node Two-pass vertical spacing
 @subsection Two-pass vertical spacing
 
+Warning: two-pass vertical spacing is deprecated and will be removed in
+a future version of LilyPond. Systems are now stretched automatically
+in a single pass. See @ref{Vertical spacing inside a system}.
+
 In order to automatically stretch systems so that they should fill the
 space left on a page, a two-pass technique can be used:
 
@@ -1184,7 +1249,7 @@ music, using the @code{\scoreTweak} music function.
     \new Staff <<
       %% Include this score tweaks:
       \scoreTweak "scoreA"
-      { \clef french c''1 \break c''1 } 
+      { \clef french c''1 \break c''1 }
     >>
     \new Staff { \clef soprano g'1 g'1 }
     \new Staff { \clef mezzosoprano e'1 e'1 }
index 25a1d9c043a7a9ba389da1413f56117d6ba6a1db..f6e1c42629d1b72a87ee8a4376b3e8aa8e86d082 100755 (executable)
@@ -14,15 +14,9 @@ except:
        print "Please specify input_file."
        sys.exit()
 
-def copyWithWarning(src, dest):
-       readFile = open(src, 'r')
-       readFileLines = readFile.readlines()
-       readFile.close()
-       writeFile = open(dest, 'w')
-       writeFile.write('%%  Do not edit this file; it is auto-generated from LSR!\n')
-       for line in readFileLines:
-               writeFile.write(line)
-       writeFile.close()
+def copy_with_warning(src, dest):
+       msg = '%%  Do not edit this file; it is auto-generated from LSR!\n'
+       open (dest, 'w').write( msg + open (src).read() )
 
 for dir in dirs:
        srcdir = os.path.join (in_dir, dir)
@@ -42,7 +36,7 @@ for dir in dirs:
        for file in file_names:
                src = os.path.join (srcdir, file)
                dest = os.path.join (destdir, file)
-               copyWithWarning(src, dest)
+               copy_with_warning(src, dest)
 #              shutil.copyfile (src, dest)
                s = os.system('lilypond -dsafe -dbackend=svg -o /tmp/lsrtest ' + dest)
                if s:
diff --git a/input/lsr/connecting/beam-across-line-breaks.ly b/input/lsr/connecting/beam-across-line-breaks.ly
new file mode 100644 (file)
index 0000000..d4113ed
--- /dev/null
@@ -0,0 +1,15 @@
+%%  Do not edit this file; it is auto-generated from LSR!
+\version "2.10.12"
+
+\header { texidoc = "
+By default, beams can't be printed across line breaks. Here's a way to
+force the line break, by setting the @code{#'breakable} property. See
+also in the manual the \"Line Breaking\" and \"Manual beams\" sections.
+" }
+
+\layout { ragged-right= ##t }
+
+\relative c''  {
+  \override Score.Beam #'breakable = ##t
+  \time 3/16 c16-[ d e \break f-] 
+}
diff --git a/input/lsr/connecting/short-tremolos.ly b/input/lsr/connecting/short-tremolos.ly
new file mode 100644 (file)
index 0000000..b409f1c
--- /dev/null
@@ -0,0 +1,16 @@
+%%  Do not edit this file; it is auto-generated from LSR!
+\version "2.10.12"
+
+\header { texidoc = "
+Short (smaller than 1/4) tremolos can be obtained; in such a case only
+one beam is connected to the stems.
+" }
+
+\layout { ragged-right = ##t }
+
+\context Staff  \relative c' {
+  \repeat "tremolo"  2 { c32 e32 }
+  \stemDown
+  \repeat "tremolo"  2 { c32 e32 }
+}
+
diff --git a/input/lsr/contemporary/feathered-beams.ly b/input/lsr/contemporary/feathered-beams.ly
new file mode 100644 (file)
index 0000000..ceaff8e
--- /dev/null
@@ -0,0 +1,20 @@
+%%  Do not edit this file; it is auto-generated from LSR!
+\version "2.10.12"
+
+\header { texidoc = "
+Feathered beams can be obtained by setting the #'grow-direction
+property; you may also want to use \featherDurations to adjust note
+durations. (See also in tha manual : \"Feathered beams\")
+" }
+
+\paper {
+  ragged-right = ##t
+  indent = #0.0
+}
+
+\featherDurations #(ly:make-moment 3 4) \relative c'' {
+  \override Beam #'grow-direction = #LEFT
+  c16[
+    c c c
+    c c c c ] 
+}
diff --git a/input/lsr/spacing/alignment-order.ly b/input/lsr/spacing/alignment-order.ly
new file mode 100644 (file)
index 0000000..f479639
--- /dev/null
@@ -0,0 +1,44 @@
+%%  Do not edit this file; it is auto-generated from LSR!
+\version "2.10.12"
+
+\header { texidoc = "
+This snippet shows of to use the @code{alignBelowContext} and
+@code{alignAboveContext} properties, which may be needed for text
+elements (e.g. lyrics) positioning, but also for musical contents such
+as ossias.
+" }
+
+% ****************************************************************
+% ly snippet:
+% ****************************************************************
+
+\paper {
+  ragged-right = ##t
+}
+
+\relative <<
+  \new Staff = "1" { c4 c s2 }
+  \new Staff = "2" { c4  c s2 }
+  \new Staff = "3" { c4  c s2 }
+  { \skip 2
+    <<
+      \lyrics {
+       \set alignBelowContext = #"1"
+       below8 first staff
+      }
+      \new Staff {
+       \set Staff.alignAboveContext = #"3"
+       \times 4/6 {
+         \override TextScript #'padding = #3
+         c8^"this" d_"staff" e^"above" d_"last" e^"staff" f
+       }
+      }
+    >> }
+>>
+
+
+
+% ****************************************************************
+% end ly snippet
+% ****************************************************************
+
index 9da4e584107f3686be11b241a654b1d3d0a8fa76..0a9eaca9cebe2bebb9b6b4dfcf0677106d7b0d26 100644 (file)
@@ -11,8 +11,8 @@ By setting @code{alignment-extra-space} or
 stretched vertically.
 
 
-For technical reasons, @code{overrideProperty} has to be used for
-setting properties on individual objects. @code{override} in a
+For technical reasons, @code{\overrideProperty} has to be used for
+setting properties on individual objects. @code{\override} in a
 @code{\context} block may still be used for global overrides. 
 " }
 
diff --git a/input/regression/arpeggio-span-one-staff.ly b/input/regression/arpeggio-span-one-staff.ly
new file mode 100644 (file)
index 0000000..7f9d3b3
--- /dev/null
@@ -0,0 +1,21 @@
+\header {
+  texidoc = "Span arpeggios within one staff also work"
+  }
+
+\version "2.11.21"
+\layout { ragged-right = ##t }
+
+\new PianoStaff <<
+ \set PianoStaff.connectArpeggios = ##t
+ \new Staff \relative c'' {
+   <<
+     {
+       c2\arpeggio
+     }
+     \\
+     {
+       g2\arpeggio a
+     }
+   >>
+ }
+>>
index 3345eb7495add07820322301edcba62598a3f716..8698e600b22631098f2cbe5d596316ce18f39fb2 100644 (file)
@@ -14,14 +14,13 @@ lengths are between 2 and 1.5."
   a,[ a]  c[ c]
   d,8[ d]  g'[ g]
   g,[ g]  d'[ d]
+  \break
   c,16[ c]  a''[ a]
   a,[ a ]  c[ c]
-  \break
   c,32[  c]  a''[ a]
   f,[ f]  e'[ e]
   c,64[ c]  a''[ a]
   f,[ f]  e'[ e]
-  \break
 }
 
 
diff --git a/input/regression/chromatic-scales.ly b/input/regression/chromatic-scales.ly
new file mode 100644 (file)
index 0000000..c16f238
--- /dev/null
@@ -0,0 +1,33 @@
+\version "2.10"
+\header{
+  texidoc="@code{staffLineLayoutFunction} is used to change the position of the notes.
+This sets @code{staffLineLayoutFunction} to @code{ly:pitch-semitones} to
+produce a chromatic scale with the distance between a consecutive
+space and line equal to one semitone.
+"
+}
+
+scales = \relative {
+  a ais b c cis d dis e f fis g gis
+  a
+}
+
+\new Staff \with {
+  \remove "Accidental_engraver"
+  \remove "Key_engraver" 
+  staffLineLayoutFunction = #ly:pitch-semitones
+  middleCPosition = #-6
+  clefGlyph = #"clefs.G"
+  clefPosition = #(+ -6 7)
+}
+{
+  \override Staff.StaffSymbol #'line-count = #5
+  \time 4/4
+  <<
+    \scales
+    \context NoteNames {
+      \set printOctaveNames= ##f
+      \scales
+    }
+  >>
+}
index 710bc54ec7e7fdaabc5ab80b34eec63948fbae2c..a49208b82d43e69881f8726bca8efe8c90933137 100644 (file)
@@ -27,7 +27,7 @@ number to 2 in order to avoid a bad page turn."
   \score {
     {
       a b c d R1
-      \repeat unfold 17 {a4 b c d}
+      \repeat unfold 26 {a4 b c d}
     }
   }
-}
\ No newline at end of file
+}
index f43184dec39f38df5a8d6a5e297bbbcc45880bfe..68dc56ce87c5537e050a5dd0b3a994d0ba32ad10 100644 (file)
@@ -17,7 +17,7 @@ long gap at the beginning or at the end of the repeat.
 \book {
   \paper {
     #(define page-breaking ly:page-turn-breaking)
-    paper-height = #80
+    paper-height = #90
     print-page-number = ##t
     print-first-page-number = ##t
   }
@@ -27,7 +27,7 @@ long gap at the beginning or at the end of the repeat.
       \set Score.skipBars = ##t
       % this should be kept on one page
       \repeat volta 2 {
-       \repeat unfold 7 {a4 b c d16 d d d} R1*10
+       \repeat unfold 6 {a4 b c d16 d d d} R1*10
        \repeat unfold 8 {a4 b c d16 d d d} \pageTurn
       }
       % use up a page
@@ -40,4 +40,4 @@ long gap at the beginning or at the end of the repeat.
       }
     }
   }
-}
\ No newline at end of file
+}
index 686622b7d5b7436deebe6acd142de23d42facf4f..f68818fb7cbe42823d35ad19f521727fd61dad55 100644 (file)
@@ -28,7 +28,7 @@ in which case the turn will go after the special barline.
     \relative c' {
       a b c d a b c d \break
       c d e f c d e f R1*4
-      \repeat unfold 15 {d4 e f g} \break
+      \repeat unfold 13 {d4 e f g} \break
       c d e f c d e f R1*2 \bar "||" R1*2
       \repeat unfold 15 {d4 e f g}
     }
index 45761f40c8a6cd7a2ffa8ec1dd83bcb1f114f971..4d885b7a38de0896773058fb10582b137315e13d 100644 (file)
@@ -188,9 +188,7 @@ Align_interface::get_extents_aligned_translates (Grob *me,
        line_break_details = me_spanner->get_bound (LEFT)->get_property ("line-break-system-details");
 
       if (!me->get_system () && !pure)
-       me->warning (_ ("vertical alignment called before line-breaking.\n"
-                       "Only do cross-staff spanners with PianoStaff."));
-
+       me->programming_error ("vertical alignment called before line-breaking");
     }
   
   Direction stacking_dir = robust_scm2dir (me->get_property ("stacking-dir"),
index 56066912fb6e156a87ba938cba89bfc1118b7592..b50111762498d5b941062e4d9b9c4534115ab790 100644 (file)
@@ -165,23 +165,6 @@ Arpeggio::pure_height (SCM smob, SCM, SCM)
   return height (smob);
 }
 
-MAKE_SCHEME_CALLBACK (Arpeggio, calc_cross_staff, 1);
-SCM
-Arpeggio::calc_cross_staff (SCM smob)
-{
-  Grob *me = unsmob_grob (smob);
-  extract_grob_set (me, "stems", stems);
-
-  for (vsize i = 1; i < stems.size (); i++)
-    {
-      Grob *s1 = Staff_symbol_referencer::get_staff_symbol (stems[i-1]);
-      Grob *s2 = Staff_symbol_referencer::get_staff_symbol (stems[i]);
-      if (s1 != s2)
-       return SCM_BOOL_T;
-    }
-  return SCM_BOOL_F;
-}
-
 ADD_INTERFACE (Arpeggio,
               "Functions and settings for drawing an arpeggio symbol (a wavy line left to noteheads.",
 
index 7b0fe264b66c35ce7d031025e392e52b2d2888fd..c18eb10c3ebf121199adb49e120e1583f639530b 100644 (file)
@@ -21,7 +21,6 @@ public:
   DECLARE_SCHEME_CALLBACK (width, (SCM));
   DECLARE_SCHEME_CALLBACK (height, (SCM));
   DECLARE_SCHEME_CALLBACK (pure_height, (SCM, SCM, SCM));
-  DECLARE_SCHEME_CALLBACK (calc_cross_staff, (SCM));
   DECLARE_GROB_INTERFACE();
 };
 
index 79e160055cad76c2c4e87d7dfe6bda76a175063a..2ecfad8d9c5c01a79f3538397c7b5ac9174839da 100644 (file)
@@ -21,9 +21,6 @@ public:
 
   Optimal_page_breaking (Paper_book *pb);
   virtual ~Optimal_page_breaking ();
-
-private:
-  Spacing_result try_page_spacing (Line_division const&);
 };
 
 #endif /* OPTIMAL_PAGE_BREAKING_HH */
index b5b3e2411367b351a60499e492f91515a2e61ad9..21edde4a692d4b5d8eb733c9a4aa3151d2918000 100644 (file)
@@ -11,6 +11,7 @@
 #define PAGE_BREAKING_HH
 
 #include "constrained-breaking.hh"
+#include "page-spacing.hh"
 
 /* Either a paper-score, markup or header.
  */
@@ -79,27 +80,38 @@ public:
   Page_breaking (Paper_book *pb, Break_predicate);
   virtual ~Page_breaking ();
 
+  bool ragged () const;
+  bool ragged_last () const;
+  bool last () const;
+  Real page_height (int page_number, bool last) const;
+
 protected:
   Paper_book *book_;
 
-  Real page_height (int page_number, bool last);
   vsize next_system (Break_position const &break_pos) const;
 
   SCM make_pages (vector<vsize> lines_per_page, SCM lines);
 
   vsize min_system_count (vsize start, vsize end);
   vsize max_system_count (vsize start, vsize end);
-  vector<Line_details> line_details (vsize start, vsize end, Line_division const &div);
+
 
   void break_into_pieces (vsize start, vsize end, Line_division const &div);
   SCM systems ();
 
-
-  vector<Line_division> line_divisions (vsize start,
-                                       vsize end,
-                                       vsize system_count,
-                                       Line_division lower_bound = Line_division (),
-                                       Line_division upper_bound = Line_division ());
+  void set_current_breakpoints (vsize start,
+                               vsize end,
+                               vsize system_count,
+                               Line_division lower_bound = Line_division (),
+                               Line_division upper_bound = Line_division ());
+  vsize current_configuration_count () const;
+  Line_division current_configuration (vsize configuration_index) const;
+  Spacing_result space_systems_on_n_pages (vsize configuration_index, vsize n, vsize first_page_num);
+  Spacing_result space_systems_on_n_or_one_more_pages (vsize configuration_index, vsize n, vsize first_page_num);
+  Spacing_result space_systems_on_best_pages (vsize configuration_index, vsize first_page_num);
+  vsize min_page_count (vsize configuration_index, vsize first_page_num);
+  bool all_lines_stretched (vsize configuration_index);
+  Real blank_page_penalty () const;
 
   SCM breakpoint_property (vsize breakpoint, char const *str);
   vector<Break_position> breaks_;
@@ -108,6 +120,19 @@ private:
   vector<Break_position> chunks_;
   vector<System_spec> all_;
   vector<Constrained_breaking> line_breaking_;
+  bool ragged_;
+  bool ragged_last_;
+
+  vector<Line_division> current_configurations_;
+  vector<Break_position> current_chunks_;
+  vsize current_start_breakpoint_;
+  vsize current_end_breakpoint_;
+
+  void cache_line_details (vsize configuration_index);
+  void clear_line_details_cache ();
+  vsize cached_configuration_index_;
+  vector<Line_details> cached_line_details_;
+  vector<Line_details> uncompressed_line_details_;
 
   vector<Break_position> chunk_list (vsize start, vsize end);
   Line_division system_count_bounds (vector<Break_position> const &chunks, bool min);
@@ -120,9 +145,12 @@ private:
   void line_divisions_rec (vsize system_count,
                           Line_division const &min,
                           Line_division const &max,
-                          vector<Line_division> *result,
                           Line_division *cur);
 
+  vector<Line_details> line_details (vsize start, vsize end, Line_division const &div);
+  Spacing_result space_systems_on_1_page (vector<Line_details> const &lines, Real page_height, bool ragged);
+  Spacing_result space_systems_on_2_pages (vsize configuration_index, vsize first_page_num);
+  Spacing_result finalize_spacing_result (vsize configuration_index, Spacing_result);
   void create_system_list ();
   void find_chunks_and_breaks (Break_predicate);
 };
index e1fa582d922fa8013e7d9535945db9f33e0feba7..7dba158c84929bfd8fa182dd39afa5415d29ddbd 100644 (file)
@@ -30,10 +30,12 @@ struct Spacing_result {
    calculations so they can be reused for querying different page counts.
 */
 
+class Page_breaking;
+
 class Page_spacer
 {
 public:
-  Page_spacer (vector<Line_details> const &lines, Real page_height, bool ragged, bool ragged_last);
+  Page_spacer (vector<Line_details> const &lines, vsize first_page_num, Page_breaking const*);
   Spacing_result solve (vsize page_count);
 
 private:
@@ -53,7 +55,8 @@ private:
     vsize prev_;
   };
 
-  Real page_height_;
+  Page_breaking const *breaker_;
+  vsize first_page_num_;
   vector<Line_details> lines_;
   Matrix<Page_spacing_node> state_;
   vsize max_page_count_;
@@ -65,29 +68,28 @@ private:
   bool calc_subproblem (vsize page, vsize lines);
 };
 
-vsize
-min_page_count (vector<Line_details> const &lines,
-               Real page_height, bool ragged, bool ragged_last);
-
-Spacing_result
-space_systems_on_n_pages (vector<Line_details> const&,
-                         vsize n,
-                         Real page_height,
-                         bool ragged,
-                         bool ragged_last);
-
-Spacing_result
-space_systems_on_n_or_one_more_pages (vector<Line_details> const&,
-                                     vsize n,
-                                     Real page_height,
-                                     Real odd_pages_penalty,
-                                     bool ragged,
-                                     bool ragged_last);
-Spacing_result
-space_systems_on_best_pages (vector<Line_details> const&,
-                            Real page_height,
-                            Real odd_pages_penalty,
-                            bool ragged,
-                            bool ragged_last);
+struct Page_spacing
+{
+  Real force_;
+  Real page_height_;
+  Real rod_height_;
+  Real spring_len_;
+  Real inverse_spring_k_;
+
+  Line_details last_line_;
+
+  Page_spacing (Real page_height)
+  {
+    page_height_ = page_height;
+    clear ();
+  }
+
+  void calc_force ();
+
+  void append_system (const Line_details &line);
+  void prepend_system (const Line_details &line);
+  void clear ();
+};
 
+Real line_space (Line_details const &line);
 #endif /* PAGE_SPACING_HH */
index db675202b6f8e138b139e745561fd0b972192d36..bdaec437061618456a3b3fa789e904faa47febc0 100644 (file)
@@ -55,9 +55,8 @@ protected:
   vsize final_page_num (Break_node const &b);
   Break_node put_systems_on_pages (vsize start,
                                   vsize end,
-                                  vector<Line_details> const &lines,
-                                  Line_division const &div,
-                                  int page_number);
+                                  vsize configuration,
+                                  vsize page_number);
 
   SCM make_lines (vector<Break_node> *breaks);
   SCM make_pages (vector<Break_node> const &breaks, SCM systems);
index 9ff982bcf854ad70e80205d455f4a2756818b3f7..3c0f7ae88eb7a4f28a065d1555ff4ffcf9c07aa9 100644 (file)
@@ -600,25 +600,3 @@ main (int argc, char **argv, char **envp)
   /* Only reachable if GUILE exits.  That is an error.  */
   return 1;
 }
-
-SCM atexit_list = SCM_EOL;
-
-LY_DEFINE (ly_atexit, "ly:atexit",
-          2, 0, 0, (SCM proc, SCM args),
-          "Just before exiting, call the procedure given. "
-"If this is called multiple times, the procedures are called "
-"in LIFO order.")
-{
-  atexit_list = scm_cons (scm_cons (proc, args), atexit_list);
-  scm_gc_protect_object (atexit_list);
-  return SCM_UNSPECIFIED;
-}
-
-LY_DEFINE (ly_do_atexit, "ly:do-atexit",
-          0, 0, 0, (),
-          "Call the atexit procedures.")
-{
-  for (SCM s = atexit_list; scm_is_pair (s); s = scm_cdr (s))
-    scm_apply_0 (scm_caar (s), scm_cdar (s));
-  return SCM_UNSPECIFIED;
-}
index a49bbbe81f64bfefb3d4d43ac1d35111a7895c44..7240d61d51e267ca9ad56a2976ba47cfd7e9ec90 100644 (file)
@@ -48,6 +48,9 @@ Note_heads_engraver::listen_note (Stream_event *ev)
 void
 Note_heads_engraver::process_music ()
 {
+  SCM c0 = get_property ("middleCPosition");
+  SCM layout_proc = get_property("staffLineLayoutFunction");
+      
   for (vsize i = 0; i < note_evs_.size (); i++)
     {
       Stream_event *ev = note_evs_[i];
@@ -61,11 +64,19 @@ Note_heads_engraver::process_music ()
        ev->origin ()->warning (_ ("NoteEvent without pitch"));
 #endif
 
-      int pos = pit ? pit->steps () : 0;
-      SCM c0 = get_property ("middleCPosition");
-      if (scm_is_number (c0))
-       pos += scm_to_int (c0);
+      int pos;
+      if (pit == 0)
+       pos = 0;
+      else if (ly_is_procedure (layout_proc)){
+       SCM pitch = ev->get_property("pitch");
+       pos = scm_to_int(scm_call_1 (layout_proc, pitch));
+      }
+      else 
+       pos = pit->steps ();
 
+      if (scm_is_number (c0))
+       pos += scm_to_int(c0);
+      
       note->set_property ("staff-position", scm_from_int (pos));
 
       /*
@@ -104,7 +115,6 @@ ADD_TRANSLATOR (Note_heads_engraver,
                /* doc */ "Generate noteheads.",
                /* create */
                "NoteHead ",
-               /* read */
-               "middleCPosition",
-               /* write */
-               "");
+               /* read */ "middleCPosition "
+               "staffLineLayoutFunction ",
+               /* write */ "");
index d18ad2837e92ffe2104f0a4ae326bea06b0cc38e..282114d5c55fa8025c2013ba548ad5c9aaf93fa3 100644 (file)
@@ -32,45 +32,6 @@ Optimal_page_breaking::~Optimal_page_breaking ()
 {
 }
 
-Spacing_result
-Optimal_page_breaking::try_page_spacing (Line_division const &line_count)
-{
-  vector<Line_details> lines = line_details (0, breaks_.size () - 1, line_count);
-  Real page_h = page_height (1, false); // FIXME
-  SCM force_sym = ly_symbol2scm ("blank-last-page-force");
-  Real blank_force = robust_scm2double (book_->paper_->lookup_variable (force_sym), 0);
-  bool ragged_all = to_boolean (book_->paper_->c_variable ("ragged-bottom"));
-  bool ragged_last = to_boolean (book_->paper_->c_variable ("ragged-last-bottom"));
-  Spacing_result ret = space_systems_on_best_pages (lines,
-                                                   page_h,
-                                                   blank_force,
-                                                   ragged_all,
-                                                   ragged_last);
-
-  /* add in the line penalties */
-  Real line_force = 0;
-  Real line_penalty = 0;
-  Real page_weighting = robust_scm2double (book_->paper_->c_variable ("page-spacing-weight"), 10);
-
-  for (vsize i = 0; i < lines.size (); i++)
-    {
-      line_force += lines[i].force_ * lines[i].force_;
-      line_penalty += lines[i].break_penalty_;
-    }
-
-  ret.demerits_ = ret.force_[0] * ret.force_[0] * page_weighting;
-  for (vsize i = 1; i < ret.force_.size (); i++)
-    ret.demerits_ += ret.force_[i] * ret.force_[i] * page_weighting;
-
-  /* for a while we tried averaging page and line forces instead of summing
-     them, but it caused the following problem. If there is a single page
-     with a very bad page force (for example because of a forced page break),
-     the page breaker will put in a _lot_ of pages so that the bad force
-     becomes averaged out over many pages. */
-  ret.demerits_ += line_force + line_penalty;
-  return ret;
-}
-
 SCM
 Optimal_page_breaking::solve ()
 {
@@ -82,36 +43,32 @@ Optimal_page_breaking::solve ()
   Spacing_result best;
   Line_division best_division;
   Line_division lower_bound;
+  vsize first_page_num = robust_scm2int (book_->paper_->c_variable ("first-page-number"), 1);
 
   for (vsize sys_count = min_sys_count;
        cur_page_count <= max_page_count && sys_count <= max_sys_count;
        sys_count++)
     {
-      Real this_best_demerits = infinity_f;
-      vector<Line_division> div = line_divisions (0, end, sys_count, lower_bound);
-      for (vsize d = 0; d < div.size (); d++)
+      Real best_demerits_for_this_sys_count = infinity_f;
+      set_current_breakpoints (0, end, sys_count, lower_bound);
+
+      for (vsize i = 0; i < current_configuration_count (); i++)
        {
-         Spacing_result cur = try_page_spacing (div[d]);
+         Spacing_result cur = space_systems_on_best_pages (i, first_page_num);
          cur_page_count = cur.systems_per_page_.size ();
          if (cur.demerits_ < best.demerits_ || isinf (best.demerits_))
            {
              best = cur;
-             best_division = div[d];
+             best_division = current_configuration (i);
            }
 
-         if (cur.demerits_ < this_best_demerits || isinf (best.demerits_))
+         if (cur.demerits_ < best_demerits_for_this_sys_count || isinf (best.demerits_))
            {
-             this_best_demerits = cur.demerits_;
-             lower_bound = div[d];
+             best_demerits_for_this_sys_count = cur.demerits_;
+             lower_bound = current_configuration (i);
            }
 
-         vector<Line_details> det = line_details (0, end, div[d]);
-         bool all_lines_stretched = true;
-         for (vsize i = 0; i < det.size (); i++)
-           if (det[i].force_ < 0)
-             all_lines_stretched = false;
-
-         if (all_lines_stretched)
+         if (all_lines_stretched (i))
            max_page_count = min (max_page_count, cur_page_count + 1);
        }
     }
index c80e0aa22317694669667fce5ed13c9cdb397a10..2cfb24bee7c5e203d366a777de967341622649cf 100644 (file)
 #include "system.hh"
 #include "warn.hh"
 
+/* for each forbidden page break, merge the systems around it into one system. */
+static vector<Line_details>
+compress_lines (const vector<Line_details> &orig)
+{
+  vector<Line_details> ret;
+
+  for (vsize i = 0; i < orig.size (); i++)
+    {
+      if (ret.size () && !scm_is_symbol (ret.back ().page_permission_))
+       {
+         Line_details const &old = ret.back ();
+         Line_details compressed = orig[i];
+         compressed.extent_[DOWN] = old.extent_[DOWN];
+         compressed.extent_[UP] = old.extent_[UP] + orig[i].extent_.length () + old.padding_;
+         compressed.space_ += old.space_;
+         compressed.inverse_hooke_ += old.inverse_hooke_;
+
+         /* we don't need the force_ field for the vertical spacing,
+            so we use force_ = n to signal that the line was compressed,
+            reducing the number of lines by n (and force_ = 0 otherwise).
+            This makes uncompression much easier. */
+         compressed.force_ = old.force_ + 1;
+         ret.back () = compressed;
+       }
+      else
+       {
+         ret.push_back (orig[i]);
+         ret.back ().force_ = 0;
+       }
+    }
+  return ret;
+}
+
+/* translate the number of systems-per-page into something meaningful for
+   the uncompressed lines.
+*/
+static vector<vsize>
+uncompress_solution (vector<vsize> const &systems_per_page,
+                    vector<Line_details> const &compressed)
+{
+  vector<vsize> ret;
+  vsize start_sys = 0;
+
+  for (vsize i = 0; i < systems_per_page.size (); i++)
+    {
+      int compressed_count = 0;
+      for (vsize j = start_sys; j < start_sys + systems_per_page[i]; j++)
+       compressed_count += (int)compressed[j].force_;
+
+      ret.push_back (systems_per_page[i] + compressed_count);
+      start_sys += systems_per_page[i];
+    }
+  return ret;
+}
+
 /* for Page_breaking, the start index (when we are dealing with the stuff
    between a pair of breakpoints) refers to the break_ index of the end of
    the previous page. So the system index of the start of the current page
@@ -41,6 +96,8 @@ Page_breaking::next_system (Break_position const &break_pos) const
 Page_breaking::Page_breaking (Paper_book *pb, Break_predicate is_break)
 {
   book_ = pb;
+  ragged_ = to_boolean (pb->paper_->c_variable ("ragged"));
+  ragged_last_ = to_boolean (pb->paper_->c_variable ("ragged-last"));
   create_system_list ();
   find_chunks_and_breaks (is_break);
 }
@@ -49,6 +106,18 @@ Page_breaking::~Page_breaking ()
 {
 }
 
+bool
+Page_breaking::ragged () const
+{
+  return ragged_;
+}
+
+bool
+Page_breaking::ragged_last () const
+{
+  return ragged_last_;
+}
+
 /* translate indices into breaks_ into start-end parameters for the line breaker */
 void
 Page_breaking::line_breaker_args (vsize sys,
@@ -121,42 +190,8 @@ Page_breaking::systems ()
   return scm_append (scm_reverse (ret));
 }
 
-vector<Line_details>
-Page_breaking::line_details (vsize start_break, vsize end_break, Line_division const &div)
-{
-  vector<Break_position> chunks = chunk_list (start_break, end_break);
-  vector<Line_details> ret;
-  assert (chunks.size () == div.size () + 1);
-
-  SCM padding_scm = book_->paper_->c_variable ("page-breaking-between-system-padding");
-  if (!scm_is_number (padding_scm))
-    padding_scm = book_->paper_->c_variable ("between-system-padding");
-  Real padding = robust_scm2double (padding_scm, 0.0);
-
-  for (vsize i = 0; i + 1 < chunks.size (); i++)
-    {
-      vsize sys = next_system (chunks[i]);
-      if (all_[sys].pscore_)
-       {
-         vsize start;
-         vsize end;
-         line_breaker_args (sys, chunks[i], chunks[i+1], &start, &end);
-
-         vector<Line_details> details = line_breaking_[sys].line_details (start, end, div[i]);
-         ret.insert (ret.end (), details.begin (), details.end ());
-       }
-      else
-       {
-         assert (div[i] == 1);
-         ret.push_back (Line_details (all_[sys].prob_));
-         ret.back ().padding_ = padding;
-       }
-    }
-  return ret;
-}
-
 Real
-Page_breaking::page_height (int page_num, bool last)
+Page_breaking::page_height (int page_num, bool last) const
 {
   SCM mod = scm_c_resolve_module ("scm page");
   SCM calc_height = scm_c_module_lookup (mod, "calc-printable-height");
@@ -372,39 +407,87 @@ Page_breaking::system_count_bounds (vector<Break_position> const &chunks, bool m
   return ret;
 }
 
-vector<Page_breaking::Line_division>
-Page_breaking::line_divisions (vsize start,
-                              vsize end,
-                              vsize system_count,
-                              Line_division lower_bound,
-                              Line_division upper_bound)
+void
+Page_breaking::set_current_breakpoints (vsize start,
+                                       vsize end,
+                                       vsize system_count,
+                                       Line_division lower_bound,
+                                       Line_division upper_bound)
 {
-  vector<Break_position> chunks = chunk_list (start, end);
+  current_chunks_ = chunk_list (start, end);
+  current_start_breakpoint_ = start;
+  current_end_breakpoint_ = end;
+  clear_line_details_cache ();
 
   if (!lower_bound.size ())
-    lower_bound = system_count_bounds (chunks, true);
+    lower_bound = system_count_bounds (current_chunks_, true);
   if (!upper_bound.size ())
-    upper_bound = system_count_bounds (chunks, false);
+    upper_bound = system_count_bounds (current_chunks_, false);
 
-  assert (lower_bound.size () == chunks.size () - 1);
-  assert (upper_bound.size () == chunks.size () - 1);
+  assert (lower_bound.size () == current_chunks_.size () - 1);
+  assert (upper_bound.size () == current_chunks_.size () - 1);
 
-  vector<Line_division> ret;
   Line_division work_in_progress;
-
+  current_configurations_.clear ();
   line_divisions_rec (system_count,
                      lower_bound,
                      upper_bound,
-                     &ret,
                      &work_in_progress);
-  return ret;
+}
+
+vsize
+Page_breaking::current_configuration_count () const
+{
+  return current_configurations_.size ();
+}
+
+void
+Page_breaking::cache_line_details (vsize configuration_index)
+{
+  if (cached_configuration_index_ != configuration_index)
+    {
+      SCM padding_scm = book_->paper_->c_variable ("page-breaking-between-system-padding");
+      if (!scm_is_number (padding_scm))
+       padding_scm = book_->paper_->c_variable ("between-system-padding");
+      Real padding = robust_scm2double (padding_scm, 0.0);
+
+      Line_division &div = current_configurations_[configuration_index];
+      uncompressed_line_details_.clear ();
+      for (vsize i = 0; i + 1 < current_chunks_.size (); i++)
+       {
+         vsize sys = next_system (current_chunks_[i]);
+         if (all_[sys].pscore_)
+           {
+             vsize start;
+             vsize end;
+             line_breaker_args (sys, current_chunks_[i], current_chunks_[i+1], &start, &end);
+
+             vector<Line_details> details = line_breaking_[sys].line_details (start, end, div[i]);
+             uncompressed_line_details_.insert (uncompressed_line_details_.end (), details.begin (), details.end ());
+           }
+         else
+           {
+             assert (div[i] == 1);
+             uncompressed_line_details_.push_back (Line_details (all_[sys].prob_));
+             uncompressed_line_details_.back ().padding_ = padding;
+           }
+       }
+      cached_line_details_ = compress_lines (uncompressed_line_details_);
+    }
+}
+
+void
+Page_breaking::clear_line_details_cache ()
+{
+  cached_configuration_index_ = VPOS;
+  cached_line_details_.clear ();
+  uncompressed_line_details_.clear ();
 }
 
 void
 Page_breaking::line_divisions_rec (vsize system_count,
                                   Line_division const &min_sys,
                                   Line_division const &max_sys,
-                                  vector<Line_division > *result,
                                   Line_division *cur_division)
 {
   vsize my_index = cur_division->size ();
@@ -433,9 +516,294 @@ Page_breaking::line_divisions_rec (vsize system_count,
     {
       cur_division->push_back (i);
       if (my_index == min_sys.size () - 1)
-        result->push_back (*cur_division);
+       current_configurations_.push_back (*cur_division);
       else
-        line_divisions_rec (system_count - i, min_sys, max_sys, result, cur_division);
+        line_divisions_rec (system_count - i, min_sys, max_sys, cur_division);
       cur_division->pop_back ();
     }
 }
+
+vsize
+Page_breaking::min_page_count (vsize configuration, vsize first_page_num)
+{
+  vsize ret = 1;
+  Real cur_rod_height = 0;
+  Real cur_spring_height = 0;
+  Real cur_page_height = page_height (first_page_num, false);
+
+  cache_line_details (configuration);
+  for (vsize i = 0; i < cached_line_details_.size (); i++)
+    {
+      Real ext_len = cached_line_details_[i].extent_.length ();
+      Real next_rod_height = cur_rod_height + ext_len
+       + ((cur_rod_height > 0) ? cached_line_details_[i].padding_: 0);
+      Real next_spring_height = cur_spring_height + line_space (cached_line_details_[i]);
+      Real next_height = next_rod_height + (ragged () ? next_spring_height : 0);
+
+
+      if ((next_height > cur_page_height && cur_rod_height > 0)
+         || (i > 0
+             && cached_line_details_[i-1].page_permission_ == ly_symbol2scm ("force")))
+       {
+         cur_rod_height = ext_len;
+         cur_spring_height = line_space (cached_line_details_[i]);
+         cur_page_height = page_height (first_page_num + ret, false);
+         ret++;
+       }
+      else
+       {
+         cur_rod_height = next_rod_height;
+         cur_spring_height = next_spring_height;
+       }
+    }
+
+  /* there are two potential problems with the last page (because we didn't know
+     it was the last page until after we managed to fit all the systems to it):
+     - we are ragged-last but the last page has a compressed spring
+     - the value returned by page_height (num, true) is smaller than the
+       value returned by page_height (num, false) and it causes the page not to
+       fit.
+
+     In either case, we just need to add one more page. This is because the last
+     line will always fit on the extra page and by adding one more page to the
+     end, the previous page is no longer the last page, so our previous
+     calculations that treated it as a non-last page were ok.
+  */
+
+  cur_page_height = page_height (first_page_num + ret - 1, true);
+  Real cur_height = cur_rod_height + ((ragged_last () || ragged ()) ? cur_spring_height : 0);
+  if (cur_height > cur_page_height
+      /* don't increase the page count if the last page had only one system */
+      && cur_rod_height > cached_line_details_.back ().extent_.length ())
+    ret++;
+
+  assert (ret <= cached_line_details_.size ());
+  return ret;
+}
+
+Spacing_result
+Page_breaking::space_systems_on_n_pages (vsize configuration, vsize n, vsize first_page_num)
+{
+  Spacing_result ret;
+  assert (n >= min_page_count (configuration, first_page_num));
+
+  cache_line_details (configuration);
+  if (n > cached_line_details_.size ())
+    return Spacing_result ();
+  if (n == 1)
+    ret = space_systems_on_1_page (cached_line_details_,
+                                  page_height (first_page_num, last ()),
+                                  ragged () || (last () && ragged_last ()));
+  else if (n == 2)
+    ret = space_systems_on_2_pages (configuration, first_page_num);
+  else
+    {
+      Page_spacer ps (cached_line_details_, first_page_num, this);
+      ret = ps.solve (n);
+    }
+
+  return finalize_spacing_result (configuration, ret);
+}
+
+Real
+Page_breaking::blank_page_penalty () const
+{
+  SCM penalty_sym = last () ? ly_symbol2scm ("blank-last-page-force") : ly_symbol2scm ("blank-page-force");
+  return robust_scm2double (book_->paper_->lookup_variable (penalty_sym), 0.0);
+}
+
+Spacing_result
+Page_breaking::space_systems_on_n_or_one_more_pages (vsize configuration, vsize n, vsize first_page_num)
+{
+  Spacing_result n_res = space_systems_on_n_pages (configuration, n, first_page_num);
+  Spacing_result m_res = space_systems_on_n_pages (configuration, n+1, first_page_num);
+  Real penalty = blank_page_penalty ();
+  n_res.demerits_ += penalty;
+  n_res.force_.back () += penalty;
+
+  if (m_res.demerits_ < n_res.demerits_)
+    return m_res;
+  return n_res;
+}
+
+Spacing_result
+Page_breaking::space_systems_on_best_pages (vsize configuration, vsize first_page_num)
+{
+  vsize min_p_count = min_page_count (configuration, first_page_num);
+  Real odd_pages_penalty = blank_page_penalty ();
+
+  cache_line_details (configuration);
+  Page_spacer ps (cached_line_details_, first_page_num, this);
+  Spacing_result best = ps.solve (min_p_count);
+  best.force_.back () += (min_p_count % 2) ? odd_pages_penalty : 0;
+  best.demerits_ += (min_p_count % 2) ? odd_pages_penalty : 0;
+
+  for (vsize i = min_p_count+1; i <= cached_line_details_.size (); i++)
+    {
+      Spacing_result cur = ps.solve (i);
+      cur.demerits_ += (i % 2) ? odd_pages_penalty : 0;
+      if (cur.demerits_ < best.demerits_)
+       best = cur;
+    }
+
+  return finalize_spacing_result (configuration, best);
+}
+
+/* Calculate demerits and fix res.systems_per_page_ so that
+   it refers to the original line numbers, not the ones given by compress_lines (). */
+Spacing_result
+Page_breaking::finalize_spacing_result (vsize configuration, Spacing_result res)
+{
+  cache_line_details (configuration);
+  res.systems_per_page_ = uncompress_solution (res.systems_per_page_, cached_line_details_);
+
+  Real line_force = 0;
+  Real line_penalty = 0;
+  Real page_force = 0;
+  Real page_weighting = robust_scm2double (book_->paper_->c_variable ("page-spacing-weight"), 10);
+
+  for (vsize i = 0; i < uncompressed_line_details_.size (); i++)
+    {
+      line_force += uncompressed_line_details_[i].force_ * uncompressed_line_details_[i].force_;
+      line_penalty += uncompressed_line_details_[i].break_penalty_;
+    }
+
+  for (vsize i = 0; i < res.force_.size (); i++)
+    {
+      Real f = res.force_[i];
+      if (isinf (f) && res.systems_per_page_[i] == 1)
+       f = 20000;
+
+      page_force += f * f;
+    }
+
+  /* for a while we tried averaging page and line forces across pages instead
+     of summing them, but it caused a problem: if there is a single page
+     with a very bad page force (for example because of a forced page break),
+     the page breaker will put in a _lot_ of pages so that the bad force
+     becomes averaged out over many pages. */
+  res.demerits_ = line_force + line_penalty + (page_force + res.penalty_) * page_weighting;
+  return res;
+
+}
+
+/* the cases for page_count = 1 or 2 can be done in O (n) time. Since they
+   are by far the most common cases, we have special functions for them.
+
+   space_systems_on_1_page has a different calling convention than most of the
+   space_systems functions. This is because space_systems_on_1_page is (unlike
+   the other space_systems functions) sometimes called on subsets of a full
+   configuration. */
+Spacing_result
+Page_breaking::space_systems_on_1_page (vector<Line_details> const &lines, Real page_height, bool ragged)
+{
+  Page_spacing space (page_height);
+  Spacing_result ret;
+
+  for (vsize i = 0; i < lines.size (); i++)
+    space.append_system (lines[i]);
+
+  ret.systems_per_page_.push_back (lines.size ());
+  ret.force_.push_back (ragged ? min (space.force_, 0.0) : space.force_);
+  ret.penalty_ = lines.back ().page_penalty_ + lines.back ().turn_penalty_;
+
+  /* don't do finalize_spacing_result () because we are only an internal function */
+  return ret;
+}
+
+Spacing_result
+Page_breaking::space_systems_on_2_pages (vsize configuration, vsize first_page_num)
+{
+  Real page1_height = page_height (first_page_num, false);
+  Real page2_height = page_height (first_page_num+1, last ());
+  bool ragged1 = ragged ();
+  bool ragged2 = ragged () || (last () && ragged_last ());
+
+  /* if there is a forced break, this reduces to 2 1-page problems */
+  cache_line_details (configuration);
+  for (vsize i = 0; i + 1 < cached_line_details_.size (); i++)
+    if (cached_line_details_[i].page_permission_ == ly_symbol2scm ("force"))
+      {
+       vector<Line_details> lines1 (cached_line_details_.begin (), cached_line_details_.begin () + i + 1);
+       vector<Line_details> lines2 (cached_line_details_.begin () + i + 1, cached_line_details_.end ());
+       Spacing_result p1 = space_systems_on_1_page (lines1, page1_height, ragged1);
+       Spacing_result p2 = space_systems_on_1_page (lines2, page2_height, ragged2);
+
+       p1.systems_per_page_.push_back (p2.systems_per_page_[0]);
+       p1.force_.push_back (p2.force_[0]);
+       p1.penalty_ += p2.penalty_ - cached_line_details_[i].turn_penalty_;
+       return p1;
+      }
+
+  vector<Real> page1_force;
+  vector<Real> page2_force;
+  Page_spacing page1 (page1_height);
+  Page_spacing page2 (page2_height);
+
+  page1_force.resize (cached_line_details_.size () - 1, infinity_f);
+  page2_force.resize (cached_line_details_.size () - 1, infinity_f);
+
+  /* find the page 1 and page 2 forces for each page-breaking position */
+  for (vsize i = 0; i < page1_force.size (); i++)
+    {
+      page1.append_system (cached_line_details_[i]);
+      page2.prepend_system (cached_line_details_[cached_line_details_.size () - 1 - i]);
+      page1_force[i] = (ragged1 && page1.force_ < 0 && i > 0) ? infinity_f : page1.force_;
+
+      if (ragged2)
+       page2_force[page2_force.size () - 1 - i] =
+         (page2.force_ < 0 && i + 1 < page1_force.size ()) ? infinity_f : 0;
+      else
+       page2_force[page2_force.size () - 1 - i] = page2.force_;
+    }
+
+  /* find the position that minimises the sum of the page forces */
+  vsize best_sys_count = 1;
+  Real best_demerits = infinity_f;
+  for (vsize i = 0; i < page1_force.size (); i++)
+    {
+      Real dem = page1_force[i] * page1_force[i]
+       + page2_force[i] * page2_force[i]
+       + cached_line_details_[i+1].page_penalty_
+       + cached_line_details_.back ().page_penalty_ + cached_line_details_.back ().turn_penalty_;
+      if (dem < best_demerits)
+       {
+         best_demerits = dem;
+         best_sys_count = i+1;
+       }
+    }
+
+  Spacing_result ret;
+  ret.systems_per_page_.push_back (best_sys_count);
+  ret.systems_per_page_.push_back (cached_line_details_.size () - best_sys_count);
+  ret.force_.push_back (page1_force[best_sys_count-1]);
+  ret.force_.push_back (page2_force[best_sys_count-1]);
+  ret.penalty_ = cached_line_details_[best_sys_count-1].page_penalty_
+    + cached_line_details_.back ().page_penalty_
+    + cached_line_details_.back ().turn_penalty_;
+
+  /* don't do finalize_spacing_result () because we are only an internal function */
+  return ret;
+}
+
+bool
+Page_breaking::all_lines_stretched (vsize configuration)
+{
+  cache_line_details (configuration);
+  for (vsize i = 0; i < cached_line_details_.size (); i++)
+    if (cached_line_details_[i].force_ < 0)
+      return false;
+
+  return true;
+}
+
+Page_breaking::Line_division
+Page_breaking::current_configuration (vsize configuration_index) const
+{
+  return current_configurations_[configuration_index];
+}
+
+bool Page_breaking::last () const
+{
+  return current_end_breakpoint_ == breaks_.size () - 1;
+}
index c3a56b098724094efa89f602e631489b24f6fd2a..028a67a9fde4d73e383f1f5fc09f32d5b7d53146 100644 (file)
 #include "page-spacing.hh"
 
 #include "matrix.hh"
+#include "page-breaking.hh"
 #include "warn.hh"
 
-/*
-  A much simplified rods-and-springs problem.
- */
-struct Page_spacing
-{
-  Real force_;
-  Real page_height_;
-  Real rod_height_;
-  Real spring_len_;
-  Real inverse_spring_k_;
-
-  Line_details last_line_;
-
-  Page_spacing (Real page_height)
-  {
-    page_height_ = page_height;
-    clear ();
-  }
-
-  void calc_force ();
-
-  void append_system (const Line_details &line);
-  void prepend_system (const Line_details &line);
-  void clear ();
-};
-
 /* In order to prevent possible division by zero, we require every line
    to have a spring of non-zero length. */
-static Real
+Real
 line_space (const Line_details &line)
 {
   return max (0.1, line.space_);
@@ -91,158 +66,15 @@ Page_spacing::clear ()
   inverse_spring_k_ = 0;
 }
 
-/* for each forbidden page break, merge the systems around it into one system. */
-static vector<Line_details>
-compress_lines (const vector<Line_details> &orig)
-{
-  vector<Line_details> ret;
-
-  for (vsize i = 0; i < orig.size (); i++)
-    {
-      if (ret.size () && !scm_is_symbol (ret.back ().page_permission_))
-       {
-         Line_details const &old = ret.back ();
-         Line_details compressed = orig[i];
-         compressed.extent_[DOWN] = old.extent_[DOWN];
-         compressed.extent_[UP] = old.extent_[UP] + orig[i].extent_.length () + old.padding_;
-         compressed.space_ += old.space_;
-         compressed.inverse_hooke_ += old.inverse_hooke_;
-
-         /* we don't need the force_ field for the vertical spacing,
-            so we use force_ = n to signal that the line was compressed,
-            reducing the number of lines by n (and force_ = 0 otherwise).
-            This makes uncompression much easier. */
-         compressed.force_ = old.force_ + 1;
-         ret.back () = compressed;
-       }
-      else
-       {
-         ret.push_back (orig[i]);
-         ret.back ().force_ = 0;
-       }
-    }
-  return ret;
-}
-
-/* translate the number of systems-per-page into something meaningful for
-   the uncompressed lines.
-*/
-static vector<vsize>
-uncompress_solution (vector<vsize> const &systems_per_page,
-                    vector<Line_details> const &compressed)
-{
-  vector<vsize> ret;
-  vsize start_sys = 0;
-
-  for (vsize i = 0; i < systems_per_page.size (); i++)
-    {
-      int compressed_count = 0;
-      for (vsize j = start_sys; j < start_sys + systems_per_page[i]; j++)
-       compressed_count += (int)compressed[j].force_;
-
-      ret.push_back (systems_per_page[i] + compressed_count);
-      start_sys += systems_per_page[i];
-    }
-  return ret;
-}
-
-/* the cases for page_count = 1 or 2 can be done in O (n) time. Since they
-   are by far the most common cases, we have special functions for them */
-static Spacing_result
-space_systems_on_1_page (vector<Line_details> const &lines, Real page_height, bool ragged)
-{
-  Page_spacing space (page_height);
-  Spacing_result ret;
-
-  for (vsize i = 0; i < lines.size (); i++)
-    space.append_system (lines[i]);
-
-  ret.systems_per_page_.push_back (lines.size ());
-  ret.force_.push_back (ragged ? min (space.force_, 0.0) : space.force_);
-  ret.penalty_ = lines.back ().page_penalty_ + lines.back ().turn_penalty_;
-  ret.demerits_ = ret.force_.back () * ret.force_.back () + ret.penalty_;
 
-  return ret;
-}
-
-static Spacing_result
-space_systems_on_2_pages (vector<Line_details> const &lines,
-                         Real page_height,
-                         bool ragged,
-                         bool ragged_last)
-{
-  /* if there is a forced break, this reduces to 2 1-page problems */
-  for (vsize i = 0; i + 1 < lines.size (); i++)
-    if (lines[i].page_permission_ == ly_symbol2scm ("force"))
-      {
-       vector<Line_details> lines1 (lines.begin (), lines.begin () + i + 1);
-       vector<Line_details> lines2 (lines.begin () + i + 1, lines.end ());
-       Spacing_result p1 = space_systems_on_1_page (lines1, page_height, ragged);
-       Spacing_result p2 = space_systems_on_1_page (lines2, page_height, ragged || ragged_last);
-
-       p1.systems_per_page_.push_back (p2.systems_per_page_[0]);
-       p1.force_.push_back (p2.force_[0]);
-       p1.penalty_ += p2.penalty_ - lines[i].turn_penalty_;
-       p1.demerits_ += p2.demerits_ - lines[i].turn_penalty_;
-       return p1;
-      }
-
-  vector<Real> page1_force;
-  vector<Real> page2_force;
-  Page_spacing page1 (page_height);
-  Page_spacing page2 (page_height);
-
-  page1_force.resize (lines.size () - 1, infinity_f);
-  page2_force.resize (lines.size () - 1, infinity_f);
-
-  for (vsize i = 0; i < page1_force.size (); i++)
-    {
-      page1.append_system (lines[i]);
-      page2.prepend_system (lines[lines.size () - 1 - i]);
-      page1_force[i] = (ragged && page1.force_ < 0 && i > 0) ? infinity_f : page1.force_;
-
-      if (ragged || ragged_last)
-       page2_force[page2_force.size () - 1 - i] =
-         (page2.force_ < 0 && i + 1 < page1_force.size ()) ? infinity_f : 0;
-      else
-       page2_force[page2_force.size () - 1 - i] = page2.force_;
-    }
-
-  vsize best_sys_count = 1;
-  Real best_demerits = infinity_f;
-  for (vsize i = 0; i < page1_force.size (); i++)
-    {
-      Real dem = page1_force[i] * page1_force[i]
-       + page2_force[i] * page2_force[i]
-       + lines[i+1].page_penalty_
-       + lines.back ().page_penalty_ + lines.back ().turn_penalty_;
-      if (dem < best_demerits)
-       {
-         best_demerits = dem;
-         best_sys_count = i+1;
-       }
-    }
-
-  Spacing_result ret;
-  ret.systems_per_page_.push_back (best_sys_count);
-  ret.systems_per_page_.push_back (lines.size () - best_sys_count);
-  ret.force_.push_back (page1_force[best_sys_count-1]);
-  ret.force_.push_back (page2_force[best_sys_count-1]);
-  ret.penalty_ = lines[best_sys_count-1].page_penalty_
-    + lines.back ().page_penalty_
-    + lines.back ().turn_penalty_;
-  ret.demerits_ = best_demerits;
-
-  return ret;
-}
-
-Page_spacer::Page_spacer (vector<Line_details> const &lines, Real page_height, bool ragged, bool ragged_last)
+Page_spacer::Page_spacer (vector<Line_details> const &lines, vsize first_page_num, Page_breaking const *breaker)
   : lines_ (lines)
 {
-  page_height_ = page_height;
+  first_page_num_ = first_page_num;
+  breaker_ = breaker;
   max_page_count_ = 0;
-  ragged_ = ragged;
-  ragged_last_ = ragged_last;
+  ragged_ = breaker->ragged ();
+  ragged_last_ = breaker->last () && breaker->ragged_last ();
 }
 
 Spacing_result
@@ -320,9 +152,10 @@ Page_spacer::resize (vsize page_count)
 bool
 Page_spacer::calc_subproblem (vsize page, vsize line)
 {
-  Page_spacing space (page_height_);
+  bool last = line == lines_.size () - 1;
+  Page_spacing space (breaker_->page_height (page + first_page_num_, last));
   Page_spacing_node &cur = state_.at (line, page);
-  bool ragged = ragged_ || (ragged_last_ && line == lines_.size () - 1);
+  bool ragged = ragged_ || (ragged_last_ && last);
 
   for (vsize page_start = line+1; page_start > page && page_start--;)
     {
@@ -364,102 +197,3 @@ Page_spacer::calc_subproblem (vsize page, vsize line)
   return !isinf (cur.demerits_);
 }
 
-vsize
-min_page_count (vector<Line_details> const &uncompressed_lines,
-               Real page_height, bool ragged, bool ragged_last)
-{
-  vsize ret = 1;
-  Real cur_rod_height = 0;
-  vector<Line_details> lines = compress_lines (uncompressed_lines);
-
-  assert (lines.size ());
-  for (vsize i = lines.size (); i--;)
-    {
-      bool rag = ragged || (ragged_last && ret == 1);
-      Real ext_len = lines[i].extent_.length ();
-      Real next_height = cur_rod_height + ext_len
-       + (rag ? line_space (lines[i]) : 0)
-       + ((cur_rod_height > 0) ? lines[i].padding_: 0);
-
-      if ((next_height > page_height && cur_rod_height > 0)
-         || (i + 1 < lines.size () && lines[i].page_permission_ == ly_symbol2scm ("force")))
-       {
-         ret++;
-         cur_rod_height = ext_len + (rag ? line_space (lines[i]) : 0);
-       }
-      else
-       cur_rod_height = next_height;
-    }
-
-  return ret;
-}
-
-Spacing_result
-space_systems_on_n_pages (vector<Line_details> const &lines,
-                         vsize n,
-                         Real page_height,
-                         bool ragged,
-                         bool ragged_last)
-{
-  vector<Line_details> compressed_lines = compress_lines (lines);
-  Spacing_result ret;
-  assert (n >= min_page_count (lines, page_height, ragged, ragged_last));
-
-  if (n > compressed_lines.size ())
-    return Spacing_result ();
-  if (n == 1)
-    ret = space_systems_on_1_page (compressed_lines, page_height, ragged || ragged_last);
-  else if (n == 2)
-    ret = space_systems_on_2_pages (compressed_lines, page_height, ragged, ragged_last);
-
-  Page_spacer ps (compressed_lines, page_height, ragged, ragged_last);
-  ret = ps.solve (n);
-
-  ret.systems_per_page_ = uncompress_solution (ret.systems_per_page_, compressed_lines);
-  return ret;
-}
-
-Spacing_result
-space_systems_on_n_or_one_more_pages (vector<Line_details> const &lines,
-                                     vsize n,
-                                     Real page_height,
-                                     Real odd_pages_penalty,
-                                     bool ragged,
-                                     bool ragged_last)
-{
-  Spacing_result n_res = space_systems_on_n_pages (lines, n, page_height, ragged, ragged_last);
-  Spacing_result m_res = space_systems_on_n_pages (lines, n+1, page_height, ragged, ragged_last);
-  n_res.demerits_ += odd_pages_penalty;
-  n_res.force_.back () += odd_pages_penalty;
-
-  if (n_res.demerits_ < m_res.demerits_)
-    return n_res;
-  return m_res;
-}
-
-Spacing_result
-space_systems_on_best_pages (vector<Line_details> const &lines,
-                            Real page_height,
-                            Real odd_pages_penalty,
-                            bool ragged,
-                            bool ragged_last)
-{
-  vector<Line_details> compressed_lines = compress_lines (lines);
-  vsize min_p_count = min_page_count (compressed_lines, page_height, ragged, ragged_last);
-
-  Page_spacer ps (compressed_lines, page_height, ragged, ragged_last);
-  Spacing_result best = ps.solve (min_p_count);
-  best.force_.back () += (min_p_count % 2) ? odd_pages_penalty : 0;
-  best.demerits_ += (min_p_count % 2) ? odd_pages_penalty : 0;
-
-  for (vsize i = min_p_count+1; i <= compressed_lines.size (); i++)
-    {
-      Spacing_result cur = ps.solve (i);
-      cur.demerits_ += (i % 2) ? odd_pages_penalty : 0;
-      if (cur.demerits_ < best.demerits_)
-       best = cur;
-    }
-
-  best.systems_per_page_ = uncompress_solution (best.systems_per_page_, compressed_lines);
-  return best;
-}
index 028856229bc00cb236f1d1003427a8b30572f367..782399542c0ab01b47ba53c5283c4d6b80e50f0b 100644 (file)
@@ -36,18 +36,10 @@ Page_turn_page_breaking::~Page_turn_page_breaking ()
 Page_turn_page_breaking::Break_node
 Page_turn_page_breaking::put_systems_on_pages (vsize start,
                                               vsize end,
-                                              vector<Line_details> const &lines,
-                                              Line_division const &div,
-                                              int page_number)
+                                              vsize configuration,
+                                              vsize page_number)
 {
-  bool last = end == breaks_.size () - 1;
-  bool ragged_all = to_boolean (book_->paper_->c_variable ("ragged-bottom"));
-  bool ragged_last = last && to_boolean (book_->paper_->c_variable ("ragged-last-bottom"));
-  Real page_h = page_height (1, false); // FIXME
-  SCM force_sym = last ? ly_symbol2scm ("blank-last-page-force") : ly_symbol2scm ("blank-page-force");
-  Real blank_force = robust_scm2double (book_->paper_->lookup_variable (force_sym), 0);
-  Real page_weighting = robust_scm2double (book_->paper_->c_variable ("page-spacing-weight"), 10);
-  int min_p_count = min_page_count (lines, page_h, ragged_all, ragged_last);
+  vsize min_p_count = min_page_count (configuration, page_number);
   bool auto_first = to_boolean (book_->paper_->c_variable ("auto-first-page-number"));
 
   /* If [START, END] does not contain an intermediate
@@ -73,14 +65,14 @@ Page_turn_page_breaking::put_systems_on_pages (vsize start,
   if (start == 0 && auto_first)
     {
       if (min_p_count % 2)
-       result = space_systems_on_n_or_one_more_pages (lines, min_p_count, page_h, 0, ragged_all, ragged_last);
+       result = space_systems_on_n_or_one_more_pages (configuration, min_p_count, page_number);
       else
-       result = space_systems_on_n_pages (lines, min_p_count, page_h, ragged_all, ragged_last);
+       result = space_systems_on_n_pages (configuration, min_p_count, page_number);
     }
   else if (page_number % 2 == min_p_count % 2)
-    result = space_systems_on_n_pages (lines, min_p_count, page_h, ragged_all, ragged_last);
+    result = space_systems_on_n_pages (configuration, min_p_count, page_number);
   else
-    result = space_systems_on_n_or_one_more_pages (lines, min_p_count, page_h, blank_force, ragged_all, ragged_last);
+    result = space_systems_on_n_or_one_more_pages (configuration, min_p_count, page_number);
 
   Break_node ret;
   ret.prev_ = start - 1;
@@ -90,22 +82,14 @@ Page_turn_page_breaking::put_systems_on_pages (vsize start,
   if (auto_first && start == 0)
     ret.first_page_number_ += 1 - (ret.page_count_ % 2);
 
-  ret.div_ = div;
+  ret.div_ = current_configuration (configuration);
   ret.system_count_ = result.systems_per_page_;
 
-  ret.too_many_lines_ = true;
-  ret.demerits_ = result.penalty_;
+  ret.too_many_lines_ = all_lines_stretched (configuration);
+  ret.demerits_ = result.demerits_;
   if (start > 0)
     ret.demerits_ += state_[start-1].demerits_;
-  for (vsize i = 0; i < lines.size (); i++)
-    {
-      ret.demerits_ += lines[i].force_ * lines[i].force_;
-      ret.demerits_ += lines[i].break_penalty_;
-      if (lines[i].force_ < 0)
-       ret.too_many_lines_ = false;
-    }
-  for (vsize i = 0; i < result.force_.size (); i++)
-    ret.demerits_ += result.force_[i] * result.force_[i] * page_weighting;
+
   return ret;
 }
 
@@ -166,14 +150,12 @@ Page_turn_page_breaking::calc_subproblem (vsize ending_breakpoint)
       min_sys_count = max (min_sys_count, prev_best_system_count);
       for (vsize sys_count = min_sys_count; sys_count <= max_sys_count && ok_page; sys_count++)
         {
-         vector<Line_division> div = line_divisions (start, end, sys_count, min_division, max_division);
+         set_current_breakpoints (start, end, sys_count, min_division, max_division);
           bool found = false;
 
-          for (vsize d = 0; d < div.size (); d++)
+          for (vsize i = 0; i < current_configuration_count (); i++)
             {
-             vector<Line_details> line = line_details (start, end, div[d]);
-
-              cur = put_systems_on_pages (start, end, line, div[d], p_num);
+              cur = put_systems_on_pages (start, end, i, p_num);
 
               if (isinf (cur.demerits_)
                  || (cur.page_count_  + (p_num % 2) > 2
@@ -195,7 +177,7 @@ Page_turn_page_breaking::calc_subproblem (vsize ending_breakpoint)
 
                  /* heuristic: if we increase the number of systems, we can bound the
                     division from below by our current best division */
-                 min_division = div[d];
+                 min_division = current_configuration (i);
                 }
             }
           if (!found && this_start_best.too_many_lines_)
index 2c291a796c8456372247998031a019422b114ae4..d583bc513b88816c781b11652fba4528dff2e559 100644 (file)
@@ -194,7 +194,7 @@ Paper_column_engraver::stop_translation_timestep ()
       command_column_->set_property ("line-break-permission", SCM_EOL);
       for (vsize i = 0; i < break_events_.size (); i++)
        {
-         SCM perm = break_events_[i]->get_property ("permission");
+         SCM perm = break_events_[i]->get_property ("break-permission");
          if (perm == ly_symbol2scm ("force") || perm == ly_symbol2scm ("allow"))
            warning (_f ("forced break was overridden by some other event, should you be using bar checks?"));
        }
index b2301d38e50e5c0c260f38d0947daff4a57d1b6c..76b4ac6ef3a440db32ff23df0e20a83e422e3476 100644 (file)
@@ -44,10 +44,8 @@ class Phrasing_slur_engraver : public Engraver
 protected:
   void acknowledge_extra_object (Grob_info);
   DECLARE_ACKNOWLEDGER (accidental);
-  DECLARE_ACKNOWLEDGER (dynamic_line_spanner);
   DECLARE_ACKNOWLEDGER (fingering);
   DECLARE_ACKNOWLEDGER (note_column);
-  DECLARE_ACKNOWLEDGER (script);
   DECLARE_ACKNOWLEDGER (slur);
   DECLARE_ACKNOWLEDGER (text_script);
   DECLARE_ACKNOWLEDGER (tie);
@@ -102,25 +100,12 @@ Phrasing_slur_engraver::acknowledge_accidental (Grob_info info)
   acknowledge_extra_object (info);
 }
 
-void
-Phrasing_slur_engraver::acknowledge_dynamic_line_spanner (Grob_info info)
-{
-  acknowledge_extra_object (info);
-}
-
 void
 Phrasing_slur_engraver::acknowledge_fingering (Grob_info info)
 {
   acknowledge_extra_object (info);
 }
 
-void
-Phrasing_slur_engraver::acknowledge_script (Grob_info info)
-{
-  if (!info.grob ()->internal_has_interface (ly_symbol2scm ("dynamic-interface")))
-    acknowledge_extra_object (info);
-}
-
 void
 Phrasing_slur_engraver::acknowledge_text_script (Grob_info info)
 {
@@ -176,10 +161,8 @@ Phrasing_slur_engraver::stop_translation_timestep ()
 }
 
 ADD_ACKNOWLEDGER (Phrasing_slur_engraver, accidental);
-ADD_ACKNOWLEDGER (Phrasing_slur_engraver, dynamic_line_spanner);
 ADD_ACKNOWLEDGER (Phrasing_slur_engraver, fingering)
 ADD_ACKNOWLEDGER (Phrasing_slur_engraver, note_column);
-ADD_ACKNOWLEDGER (Phrasing_slur_engraver, script);
 ADD_ACKNOWLEDGER (Phrasing_slur_engraver, slur);
 ADD_ACKNOWLEDGER (Phrasing_slur_engraver, text_script);
 ADD_ACKNOWLEDGER (Phrasing_slur_engraver, tie);
index a465b7da1141551eb63a811baed536d274a03cfc..fa2e91eec363d3c3b437ad2c20da41378bd22ed2 100644 (file)
@@ -58,7 +58,10 @@ Span_arpeggio_engraver::process_acknowledged ()
   */
   if (!span_arpeggio_ && arpeggios_.size () > 1
       && to_boolean (get_property ("connectArpeggios")))
-    span_arpeggio_ = make_item ("Arpeggio", SCM_EOL);
+    {
+      span_arpeggio_ = make_item ("Arpeggio", SCM_EOL);
+      span_arpeggio_->set_property ("cross-staff", SCM_BOOL_T);
+    }
 }
 
 void
@@ -89,6 +92,8 @@ Span_arpeggio_engraver::stop_translation_timestep ()
          arpeggios_[j]->set_property ("transparent", SCM_BOOL_T);
        }
 
+
+      span_arpeggio_->set_parent (arpeggios_[0]->get_parent (Y_AXIS), Y_AXIS);
       span_arpeggio_ = 0;
     }
   arpeggios_.clear ();
index 663d654e0b67cd8c916c26ccf061da51fa45c9ee..e700615523045a4882030f00cf08e8bf73e56d45 100644 (file)
@@ -402,7 +402,7 @@ System::get_paper_system ()
 
   /* information that the page breaker might need */
   Grob *right_bound = this->get_bound (RIGHT);
-  pl->set_property ("skylines", this->get_property ("skylines"));
+  pl->set_property ("vertical-skylines", this->get_property ("vertical-skylines"));
   pl->set_property ("page-break-permission", right_bound->get_property ("page-break-permission"));
   pl->set_property ("page-turn-permission", right_bound->get_property ("page-turn-permission"));
   pl->set_property ("page-break-penalty", right_bound->get_property ("page-break-penalty"));
index dd82a1d8e1fae32a8f7821d4ace8bab6fade03aa..0d56bb44bb12b427dcc883cfeecb42141b4180a7 100644 (file)
@@ -67,11 +67,10 @@ Tab_note_heads_engraver::process_music ()
   for (vsize i = 0; i < note_events_.size (); i++)
     {
       SCM string_tunings = get_property ("stringTunings");
-      int number_of_strings = scm_ilength (string_tunings);
+      int string_count = scm_ilength (string_tunings);
       bool high_string_one = to_boolean (get_property ("highStringOne"));
 
       Stream_event *event = note_events_[i];
-      Item *note = make_item ("TabNoteHead", event->self_scm ());
 
       Stream_event *tabstring_event = 0;
 
@@ -91,53 +90,55 @@ Tab_note_heads_engraver::process_music ()
            j++;
        }
 
-      int tab_string;
-      bool string_found;
+      int string_number = 0;
       if (tabstring_event)
-       {
-         tab_string = scm_to_int (tabstring_event->get_property ("string-number"));
-         string_found = true;
-       }
-      else
-       {
-         tab_string = high_string_one ? 1 : number_of_strings;
-         string_found = false;
-       }
-
-      Duration dur = *unsmob_duration (event->get_property ("duration"));
-
-      SCM scm_pitch = event->get_property ("pitch");
-      SCM proc = get_property ("tablatureFormat");
-      SCM min_fret_scm = get_property ("minimumFret");
-      int min_fret = scm_is_number (min_fret_scm) ? scm_to_int (min_fret_scm) : 0;
+       string_number = scm_to_int (tabstring_event->get_property ("string-number"));
 
-      while (!string_found)
+      if (!string_number)
        {
-         int fret = unsmob_pitch (scm_pitch)->rounded_semitone_pitch ()
-           - scm_to_int (scm_list_ref (string_tunings, scm_from_int (tab_string - 1)));
-         if (fret < min_fret)
-           tab_string += high_string_one ? 1 : -1;
-         else
-           string_found = true;
+         SCM scm_pitch = event->get_property ("pitch");
+         int min_fret = robust_scm2int (get_property ("minimumFret"), 0);
+         int start = (high_string_one) ? 1 : string_count;
+         int end = (high_string_one) ? string_count : 1;
+
+         int i = start;
+         do
+           {
+             int fret = unsmob_pitch (scm_pitch)->rounded_semitone_pitch ()
+               - scm_to_int (robust_list_ref (i - 1, string_tunings));
+         
+             if (fret >= min_fret)
+               {
+                 string_number = i;
+                 break;
+               }
+             i += high_string_one ? 1 : -1;
+           }
+         while (i != end);
        }
+      
+      if (string_number)
+       {
+         SCM proc = get_property ("tablatureFormat");
+         SCM text = scm_call_3 (proc, scm_from_int (string_number),
+                                context ()->self_scm (),
+                                event->self_scm ());
+         Item *note = make_item ("TabNoteHead", event->self_scm ());
+         note->set_property ("text", text);
 
-      SCM text = scm_call_3 (proc, scm_from_int (tab_string),
-                            context ()->self_scm (),
-                            event->self_scm ());
-      note->set_property ("text", text);
-
-
-      int pos = 2 * tab_string - number_of_strings - 1; // No tab-note between the string !!!
-      if (to_boolean (get_property ("stringOneTopmost")))
-       pos = -pos;
 
-      note->set_property ("staff-position", scm_from_int (pos));
+         int pos = 2 * string_number - string_count - 1; // No tab-note between the string !!!
+         if (to_boolean (get_property ("stringOneTopmost")))
+           pos = - pos;
 
+         note->set_property ("staff-position", scm_from_int (pos));
       
-      notes_.push_back (note);
+         notes_.push_back (note);
+       }
+      else
+       event->origin ()->warning ("could not calculate a string number.");
     }
 }
-
 void
 Tab_note_heads_engraver::stop_translation_timestep ()
 {
index 3623d0ace805cc497e20e30ab0e6876ba91a57b1..cae11b1a29a191af49a56e78c80e325c915c4613 100644 (file)
@@ -22,7 +22,7 @@
 #(define (whitelist-grob str)
   (set! grob-whitelist (cons str grob-whitelist)))
 
-#(define graph (make-graph (format "~a.dot" (ly:parser-output-name parser))))
+#(define graph (make-empty-graph (ly:parser-output-name parser)))
 
 #(define (grob-name g)
   (let* ((meta (ly:grob-property g 'meta))
index 0197dfea479ccadd62a70e88e2600a00e009daac..1d0b28cf6ca3a295de73bbf82b08076e0dfc0d78 100644 (file)
@@ -380,6 +380,7 @@ up the interpretation phase. This speeds up debugging large scores.")
      (squashedPosition ,integer? " Vertical position of
 squashing for @internalsref{Pitch_squash_engraver}.")
 
+     (staffLineLayoutFunction ,procedure? "Layout of staff lines, 'traditional, or 'semitone.")
      (stringNumberOrientations ,list? "See @code{fingeringOrientations}")
      (strokeFingerOrientations ,list? "See @code{fingeringOrientations}")
      (stringOneTopmost ,boolean? "Whether the 1st string is printed on the
index 82d377ccdce1b125f6b2fe54fcc7071b0c415313..196b5501584c3956287745533d28756d798725b2 100644 (file)
        (script-priority . 0)
        (side-axis . ,X)
        (staff-position . 0.0)
-       (cross-staff . ,ly:arpeggio::calc-cross-staff)
        (Y-extent . ,ly:arpeggio::height)
        (meta . ((class . Item)
                 (interfaces . (arpeggio-interface
index f5db38b7a800a52d13f614411dc0707626784bee..c2801633a80dc4e70d86cfc1b451957a5f05a715 100644 (file)
@@ -8,19 +8,21 @@
 (define-module (scm graphviz)
   #:use-module (lily)
   #:export
-  (make-graph add-node add-edge add-cluster
-             graph-write
-             ))
+  (make-empty-graph add-node add-edge add-cluster
+                   graph-write
+                   ))
 
-(define (make-graph filename)
-   #(() () () ()))
+(define graph-type (make-record-type "graph" '(nodes edges clusters name)))
 
+(define make-graph (record-constructor graph-type))
+(define (make-empty-graph name) (make-graph '() '() '() name))
 
-;; fixme: use structs/records.
-;; fixme add & use setters.
-(define (nodes g) (vector-ref g 1))
-(define (edges g) (vector-ref g 2))
-(define (clusters g) (vector-ref g 3))
+(define nodes (record-accessor graph-type 'nodes))
+(define edges (record-accessor graph-type 'edges))
+(define clusters (record-accessor graph-type 'clusters))
+(define set-nodes! (record-modifier graph-type 'nodes))
+(define set-edges! (record-modifier graph-type 'edges))
+(define set-clusters! (record-modifier graph-type 'clusters))
 
 (define (add-cluster graph node-id cluster-name)
   (let* ((cs (clusters graph))
         (already-in-cluster (if cluster
                                 (cdr cluster)
                                 '())))
-    (vector-set! graph 3 (assq-set! cs
+    (set-clusters! graph (assq-set! cs
                                    cluster-name
                                    (cons node-id already-in-cluster)))))
 
 (define (add-node graph label . cluster-name)
   (let* ((ns (nodes graph))
          (id (length ns)))
-    (vector-set! graph 1 (cons `(,id . ,label) ns))
+    (set-nodes! graph (assq-set! ns id label))
     (if (and (not (null? cluster-name))
             (string? (car cluster-name)))
        (add-cluster graph id (car cluster-name)))
     id))
 
 (define (add-edge graph node1 node2)
-  (vector-set! graph 2 (cons `(,node1 . ,node2) (edges graph))))
+  (set-edges! graph (cons `(,node1 . ,node2) (edges graph))))
 
 (define (graph-write graph out)
   (let ((ns (nodes graph))
index 4afe0fb8beec66b981e74ef61e189eaa96bc0e17..48d911751aff6fbda380a2a6f4c735cc5e960704 100644 (file)
@@ -649,7 +649,6 @@ The syntax is the same as `define*-public'."
          (ly:error (_ "failed files: ~S") (string-join failed))
          (exit 1))
        (begin
-         (ly:do-atexit)
          ;; HACK: be sure to exit with single newline
          (ly:message "")
          (exit 0)))))