]> git.donarmstrong.com Git - lilypond.git/commitdiff
Merge branch 'master' into nested-bookparts
authorNicolas Sceaux <nicolas.sceaux@free.fr>
Tue, 11 Nov 2008 15:57:57 +0000 (16:57 +0100)
committerNicolas Sceaux <nicolas.sceaux@free.fr>
Tue, 11 Nov 2008 15:57:57 +0000 (16:57 +0100)
21 files changed:
input/new/book-parts.ly [new file with mode: 0644]
input/regression/bookparts.ly [new file with mode: 0644]
lily/book-scheme.cc
lily/book.cc
lily/include/book.hh
lily/include/lily-parser.hh
lily/include/paper-book.hh
lily/lily-lexer.cc
lily/lily-parser.cc
lily/page-breaking.cc
lily/paper-book-scheme.cc
lily/paper-book.cc
lily/parser.yy
ly/declarations-init.ly
ly/init.ly
ly/titling-init.ly
scm/layout-page-layout.scm
scm/lily-library.scm
scm/midi.scm
scm/page.scm
scm/titling.scm

diff --git a/input/new/book-parts.ly b/input/new/book-parts.ly
new file mode 100644 (file)
index 0000000..1b4754d
--- /dev/null
@@ -0,0 +1,64 @@
+\version "2.11.63"
+
+\header {
+  lsrtags = "paper-and-layout"
+  texidocs = "@code{\\bookpart} can be used to split a book into
+several parts.
+Each part last page can be affected by @code{ragged-bottom-last}.
+Header and footer markups can detect a part last page, and make the
+difference with the book last page.
+"
+  doctitle = "Book parts"
+}
+
+#(set-default-paper-size "a6")
+
+\book {
+
+  %% book paper, which is inherited by all children bookparts
+  \paper {
+    ragged-last-bottom = ##t
+    %% Page footer: add a different part-tagline at part last page
+    oddFooterMarkup = \markup {
+      \column {
+        \fill-line {
+          %% Copyright header field only on book first page.
+          \on-the-fly #first-page \fromproperty #'header:copyright
+        }
+        \fill-line {
+          %% Part tagline header field only on each part last page.
+          \on-the-fly #part-last-page \fromproperty #'header:parttagline
+        }
+        \fill-line {
+          %% Tagline header field only on book last page.
+          \on-the-fly #last-page \fromproperty #'header:tagline
+        }
+      }
+    }
+  }
+
+  %% book header, which is inherited by the first bookpart
+  \header {
+    title = "Book title"
+    copyright = "Copyright line on book first page"
+    parttagline = "Part tagline"
+    tagline = "Book tagline"
+  }
+  
+  \bookpart {
+    %% a different page breaking function may be used on each part
+    \paper { #(define page-breaking optimal-page-breaks) }
+    \header { subtitle = "First part" }
+    \markup { The first book part }
+    \markup { a page break }
+    \pageBreak
+    \markup { first part last page }
+    \markup \wordwrap { with ragged-last-bottom (see the space below this text) }
+  }
+
+  \bookpart {
+    \header { subtitle = "Second part" }
+    { c' }
+  }
+
+}
diff --git a/input/regression/bookparts.ly b/input/regression/bookparts.ly
new file mode 100644 (file)
index 0000000..a612a0f
--- /dev/null
@@ -0,0 +1,39 @@
+\version "2.11.63"
+
+\header {
+  texidoc = "A book can be split into several parts with different paper settings,
+using @code{\\bookpart}.
+
+Fonts are loaded into the top-level paper.
+Page labels are also collected into the top-level paper."
+}
+
+#(set-default-paper-size "a6")
+
+#(define-markup-command (roman-page-number layout props) ()
+  (let ((page-number (chain-assoc-get 'page:page-number props)))
+    (interpret-markup layout props (format #f "~@r" page-number))))
+
+\book {
+  \tocItem \markup "First part"
+  \header { title = "Book with several parts" }
+  \markup { First part }
+  \markup { with default paper settings. }
+
+  \bookpart {
+    \paper {
+      left-margin = 20\mm
+      right-margin = 20\mm
+      line-width = 65\mm
+      evenHeaderMarkup = \markup \fill-line { \roman-page-number "SECOND PART" \null }
+      oddHeaderMarkup = \markup \fill-line { \null "SECOND PART" \roman-page-number }
+    }
+    \tocItem \markup "Second part"
+    \markup \justify { Second part, with different margins and page header. }
+    { c' }
+  }
+
+  \tocItem \markup "Third part"
+  \markup { Third part }
+  \markuplines \table-of-contents
+}
index e00f1ded496965f1882390f31976f613b26debb7..58a05650611adeb383276f44953f3a93cc62b747 100644 (file)
@@ -34,6 +34,18 @@ LY_DEFINE (ly_make_book, "ly:make-book",
   return x;
 }
 
+LY_DEFINE (ly_make_book_part, "ly:make-book-part",
+          1, 0, 0, (SCM scores),
+          "Make a @code{\\bookpart} containing @code{\\scores}.")
+{
+  Book *book = new Book;
+  book->scores_ = scm_append (scm_list_2 (scores, book->scores_));
+
+  SCM x = book->self_scm ();
+  book->unprotect ();
+  return x;
+}
+
 LY_DEFINE (ly_book_process, "ly:book-process",
           4, 0, 0, (SCM book_smob,
                     SCM default_paper,
@@ -96,3 +108,13 @@ LY_DEFINE (ly_book_add_score_x, "ly:book-add-score!",
   book->add_score (score);
   return SCM_UNSPECIFIED;
 }
+
+LY_DEFINE (ly_book_add_bookpart_x, "ly:book-add-bookpart!",
+          2, 0, 0, (SCM book_smob, SCM book_part),
+          "Add @var{book_part} to @var{book-smob} book part list.")
+{
+  LY_ASSERT_SMOB (Book, book_smob, 1);
+  Book *book = unsmob_book (book_smob); 
+  book->add_bookpart (book_part);
+  return SCM_UNSPECIFIED;
+}
index 335507601d37fc46d3e1fa381e904b4b27421f82..96243e1b954647127c7dc50d4bd51ed1293618cb 100644 (file)
@@ -29,6 +29,7 @@ Book::Book ()
   paper_ = 0;
   header_ = SCM_EOL;
   scores_ = SCM_EOL;
+  bookparts_ = SCM_EOL;
   input_location_ = SCM_EOL;
   smobify_self ();
 
@@ -40,6 +41,7 @@ Book::Book (Book const &s)
   paper_ = 0;
   header_ = SCM_EOL;
   scores_ = SCM_EOL;
+  bookparts_ = SCM_EOL;
   input_location_ = SCM_EOL;
   smobify_self ();
 
@@ -64,6 +66,16 @@ Book::Book (Book const &s)
       t = SCM_CDRLOC (*t);
       newscore->unprotect ();
     }
+
+  t = &bookparts_;
+  for (SCM p = s.bookparts_; scm_is_pair (p); p = scm_cdr (p))
+    {
+      Book *newpart = unsmob_book (scm_car (p))->clone ();
+
+      *t = scm_cons (newpart->self_scm (), SCM_EOL);
+      t = SCM_CDRLOC (*t);
+      newpart->unprotect ();
+    }
 }
 
 Input *
@@ -87,6 +99,7 @@ Book::mark_smob (SCM s)
   if (book->paper_)
     scm_gc_mark (book->paper_->self_scm ());
   scm_gc_mark (book->scores_);
+  scm_gc_mark (book->bookparts_);
   scm_gc_mark (book->input_location_);
   
   return book->header_;
@@ -105,62 +118,166 @@ Book::add_score (SCM s)
   scores_ = scm_cons (s, scores_);
 }
 
+void
+Book::set_parent (Book *parent)
+{
+  if (!paper_)
+    {
+      paper_ = new Output_def ();
+      paper_->unprotect ();
+    }
+  paper_->parent_ = parent->paper_;
+  /* If this part is the first child of parent, copy its header */
+  if (ly_is_module (parent->header_) && (scm_is_null (parent->bookparts_)))
+    {
+      SCM tmp_header = ly_make_anonymous_module (false);
+      ly_module_copy (tmp_header, parent->header_);
+      if (ly_is_module (header_))
+        ly_module_copy (tmp_header, header_);
+      header_ = tmp_header;
+    }
+}
 
-/* Concatenate all score outputs into a Paper_book
+/* Before an explicit \bookpart is encountered, scores are added to the book.
+ * But once a bookpart is added, the previous scores shall be collected into
+ * a new bookpart.
  */
-Paper_book *
-Book::process (Output_def *default_paper,
-              Output_def *default_layout)
+void
+Book::add_scores_to_bookpart ()
+{
+  if (scm_is_pair (scores_))
+    {
+      /* If scores have been added to this book, add them to a child 
+       * book part */
+      Book *part = new Book;
+      part->set_parent (this);
+      part->scores_ = scores_;
+      bookparts_ = scm_cons (part->self_scm (), bookparts_);
+      part->unprotect ();
+      scores_ = SCM_EOL;
+    }
+}
+
+void
+Book::add_bookpart (SCM b)
+{
+  add_scores_to_bookpart ();
+  Book *part = unsmob_book (b);
+  part->set_parent (this);
+  bookparts_ = scm_cons (b, bookparts_);
+}
+
+bool
+Book::error_found ()
 {
   for (SCM s = scores_; scm_is_pair (s); s = scm_cdr (s))
     if (Score *score = unsmob_score (scm_car (s)))
       if (score->error_found_)
-       return 0;
+       return true;
+  
+  for (SCM part = bookparts_; scm_is_pair (part); part = scm_cdr (part))
+    if (Book *bookpart = unsmob_book (scm_car (part)))
+      if (bookpart->error_found ())
+       return true;
+
+  return false;
+}
+
+Paper_book *
+Book::process (Output_def *default_paper,
+              Output_def *default_layout)
+{
+  return process (default_paper, default_layout, 0);
+}
+
+void
+Book::process_bookparts (Paper_book *output_paper_book, Output_def *paper, Output_def *layout)
+{
+  add_scores_to_bookpart ();
+  for (SCM p = scm_reverse (bookparts_); scm_is_pair (p); p = scm_cdr (p))
+    {
+      if (Book *book = unsmob_book (scm_car (p)))
+        {
+          Paper_book *paper_book_part = book->process (paper, layout, output_paper_book);
+          if (paper_book_part)
+            output_paper_book->add_bookpart (paper_book_part->self_scm ());
+        }
+    }
+}
 
+void
+Book::process_score (SCM s, Paper_book *output_paper_book, Output_def *layout)
+{
+  if (Score *score = unsmob_score (scm_car (s)))
+    {
+      SCM outputs = score
+       ->book_rendering (output_paper_book->paper_, layout);
+             
+      while (scm_is_pair (outputs))
+       {
+         Music_output *output = unsmob_music_output (scm_car (outputs));
+                 
+         if (Performance *perf = dynamic_cast<Performance *> (output))
+           output_paper_book->add_performance (perf->self_scm ());
+         else if (Paper_score *pscore = dynamic_cast<Paper_score *> (output))
+           {
+             if (ly_is_module (score->get_header ()))
+               output_paper_book->add_score (score->get_header ());
+             output_paper_book->add_score (pscore->self_scm ());
+           }
+                 
+         outputs = scm_cdr (outputs);
+       }
+    }
+  else if (Text_interface::is_markup_list (scm_car (s))
+          || unsmob_page_marker (scm_car (s)))
+    output_paper_book->add_score (scm_car (s));
+  else
+    assert (0);
+    
+}
+
+/* Concatenate all score or book part outputs into a Paper_book
+ */
+Paper_book *
+Book::process (Output_def *default_paper,
+              Output_def *default_layout,
+              Paper_book *parent_part)
+{
   Output_def *paper = paper_ ? paper_ : default_paper;
+
+  /* If top book, recursively check score errors */
+  if (!parent_part && error_found ())
+    return 0;
+
   if (!paper)
     return 0;
-  
+
   Paper_book *paper_book = new Paper_book ();
   Real scale = scm_to_double (paper->c_variable ("output-scale"));
   Output_def *scaled_bookdef = scale_output_def (paper, scale);
-
   paper_book->paper_ = scaled_bookdef;
-  scaled_bookdef->unprotect ();
-
+  if (parent_part)
+    {
+      paper_book->parent_ = parent_part;
+      paper_book->paper_->parent_ = parent_part->paper_;
+    }
   paper_book->header_ = header_;
 
-  /* Render in order of parsing.  */
-  for (SCM s = scm_reverse (scores_); scm_is_pair (s); s = scm_cdr (s))
+  if (scm_is_pair (bookparts_))
     {
-      if (Score *score = unsmob_score (scm_car (s)))
-       {
-         SCM outputs = score
-           ->book_rendering (paper_book->paper_, default_layout);
-
-         while (scm_is_pair (outputs))
-           {
-             Music_output *output = unsmob_music_output (scm_car (outputs));
-
-             if (Performance *perf = dynamic_cast<Performance *> (output))
-               paper_book->add_performance (perf->self_scm ());
-             else if (Paper_score *pscore = dynamic_cast<Paper_score *> (output))
-               {
-                 if (ly_is_module (score->get_header ()))
-                   paper_book->add_score (score->get_header ());
-                 paper_book->add_score (pscore->self_scm ());
-               }
-
-             outputs = scm_cdr (outputs);
-           }
-       }
-      else if (Text_interface::is_markup_list (scm_car (s))
-              || unsmob_page_marker (scm_car (s)))
-       paper_book->add_score (scm_car (s));
-      else
-       assert (0);
+      /* Process children book parts */
+      process_bookparts (paper_book, paper, default_layout);
+    }
+  else
+    {
+      /* Process scores */
+  /* Render in order of parsing.  */
+      for (SCM s = scm_reverse (scores_); scm_is_pair (s); s = scm_cdr (s))
+        {
+          process_score (s, paper_book, default_layout);
+        }
     }
 
   return paper_book;
 }
-
index cf478432388fea996d8a35224815a64d1a56de57..a29cb074498a2e8bc9304a94a7a9cb8e52c2251c 100644 (file)
@@ -24,6 +24,7 @@ public:
   SCM header_;
   Output_def *paper_;
   SCM scores_;
+  SCM bookparts_;
   SCM input_location_;
 
   Book (Book const &);
@@ -31,9 +32,24 @@ public:
   VIRTUAL_COPY_CONSTRUCTOR(Book, Book);
   Book ();
   void add_score (SCM);
+  void add_bookpart (SCM);
   Paper_book *process (Output_def *def_paper,
                       Output_def *def_layout);
+  Paper_book *process (Output_def *default_paper,
+                      Output_def *default_layout,
+                      Paper_book *parent_part);
   void set_keys ();
+
+protected:
+  void set_parent (Book *parent);
+  void add_scores_to_bookpart ();
+  bool error_found ();
+  void process_score (SCM score,
+                     Paper_book *output_paper_book,
+                     Output_def *layout);
+  void process_bookparts (Paper_book *output_paper_book,
+                         Output_def *paper,
+                         Output_def *layout);
 };
 
 DECLARE_UNSMOB (Book, book);
index ed4673de78e6a3be16ac8f1a1a2f82aabc0c6af2..c73f8f7991faedd86fd1d7243895dfa0c006fbf0 100644 (file)
@@ -74,6 +74,9 @@ SCM ly_parser_scorify (SCM, SCM);
 Output_def *get_layout (Lily_parser *parser);
 Output_def *get_midi (Lily_parser *parser);
 Output_def *get_paper (Lily_parser *parser);
+void stack_paper (Lily_parser *parser, Output_def *paper);
+void unstack_paper (Lily_parser *parser);
+void set_paper (Lily_parser *parser, Output_def *paper);
 SCM get_header (Lily_parser *parser);
 
 #endif /* LILY_PARSER_HH */
index 4ea192794603b6fe9d021c911c21e36aed0bbb72..d06f8fdd7c7306e13515d95f02d50462750ece27 100644 (file)
@@ -31,11 +31,16 @@ public:
   SCM header_;
   SCM header_0_;
   SCM scores_;
+  SCM bookparts_;
+  Paper_book *parent_;
   Output_def *paper_;
 
   Paper_book ();
 
+  Output_def *top_paper ();
+
   void add_score (SCM);
+  void add_bookpart (SCM);
   void add_performance (SCM);
 
   SCM performances () const;
@@ -49,6 +54,14 @@ public:
   
   void classic_output (SCM output_channel);
   void output (SCM output_channel);
+
+protected:
+  void classic_output_aux (SCM output,
+                          int *first_performance_number);
+  void output_aux (SCM output_channel,
+                  bool is_last,
+                  int *first_page_number,
+                  int *first_performance_number);
 };
 
 DECLARE_UNSMOB (Paper_book, paper_book)
index 7b77d58922b6816c55607a1d30c9c0f622ae87d1..374eed4ec812dc51ab33a66994b7a70fc168f164 100644 (file)
@@ -31,6 +31,7 @@ static Keyword_ent the_key_tab[]
   {"alias", ALIAS},
   {"alternative", ALTERNATIVE},
   {"book", BOOK},
+  {"bookpart", BOOKPART},
   {"change", CHANGE},
   {"chordmode", CHORDMODE},
   {"chords", CHORDS},
index 13d62ebc5c762eb68873bace69250e14687026dd..7e414916654ae9c3bc721637dc24b7bebeec0320 100644 (file)
@@ -221,17 +221,46 @@ get_midi (Lily_parser *parser)
   return layout;
 }
 
+/* Return a copy of the top of $papers stack, or $defaultpaper if the
+ * stack is empty */
 Output_def *
 get_paper (Lily_parser *parser)
 {
-  SCM id = parser->lexer_->lookup_identifier ("$defaultpaper");
-  Output_def *layout = unsmob_output_def (id);
+  SCM papers = parser->lexer_->lookup_identifier ("$papers");
+  Output_def *layout = ((papers == SCM_UNDEFINED) || scm_is_null (papers)) ?
+    0 : unsmob_output_def (scm_car (papers));
+  SCM default_paper = parser->lexer_->lookup_identifier ("$defaultpaper");
+  layout = layout ? layout : unsmob_output_def (default_paper);
 
   layout = layout ? dynamic_cast<Output_def *> (layout->clone ()) : new Output_def;
   layout->set_variable (ly_symbol2scm ("is-paper"), SCM_BOOL_T);
   return layout;
 }
 
+/* Stack a paper on top of $papers */
+void
+stack_paper (Lily_parser *parser, Output_def *paper)
+{
+  parser->lexer_->set_identifier (ly_symbol2scm ("$papers"),
+                                  scm_cons (paper->self_scm (),
+                                            parser->lexer_->lookup_identifier ("$papers")));
+}
+
+/* Unstack a paper from $papers */
+void
+unstack_paper (Lily_parser *parser)
+{
+  parser->lexer_->set_identifier (ly_symbol2scm ("$papers"),
+                                  scm_cdr (parser->lexer_->lookup_identifier ("$papers")));
+}
+
+/* Change the paper on top of $papers */
+void
+set_paper (Lily_parser *parser, Output_def *paper)
+{
+  scm_set_car_x (parser->lexer_->lookup_identifier ("$papers"), paper->self_scm ());
+}
+
 SCM
 get_header (Lily_parser *parser)
 {
index 1ae769e82d641d79145e53491bd77795baf2d4a4..a111d933e5ed27e25dccce1096df5cdbd14e2034 100644 (file)
@@ -212,6 +212,7 @@ Page_breaking::systems ()
 Real
 Page_breaking::page_height (int page_num, bool last) const
 {
+  bool last_part = ly_scm2bool (book_->paper_->c_variable ("is-last-bookpart"));
   SCM mod = scm_c_resolve_module ("scm page");
   SCM calc_height = scm_c_module_lookup (mod, "calc-printable-height");
   SCM make_page = scm_c_module_lookup (mod, "make-page");
@@ -222,7 +223,8 @@ Page_breaking::page_height (int page_num, bool last) const
   SCM page = scm_apply_0 (make_page, scm_list_n (
                   book_->self_scm (),
                   ly_symbol2scm ("page-number"), scm_from_int (page_num),
-                  ly_symbol2scm ("is-last"), scm_from_bool (last),
+                  ly_symbol2scm ("is-last-bookpart"), scm_from_bool (last_part),
+                  ly_symbol2scm ("is-bookpart-last-page"), scm_from_bool (last),
                   SCM_UNDEFINED));
   SCM height = scm_apply_1 (calc_height, page, SCM_EOL);
   return scm_to_double (height) - page_top_space_;
@@ -254,21 +256,24 @@ Page_breaking::make_pages (vector<vsize> lines_per_page, SCM systems)
   SCM book = book_->self_scm ();
   int first_page_number
     = robust_scm2int (book_->paper_->c_variable ("first-page-number"), 1);
+  bool last_bookpart = ly_scm2bool (book_->paper_->c_variable ("is-last-bookpart"));
   SCM ret = SCM_EOL;
-  SCM label_page_table = SCM_EOL;
+  SCM label_page_table = book_->top_paper ()->c_variable ("label-page-table");
+  if (label_page_table == SCM_UNDEFINED)
+    label_page_table = SCM_EOL;
 
   for (vsize i = 0; i < lines_per_page.size (); i++)
     {
       SCM page_num = scm_from_int (i + first_page_number);
-      SCM last = scm_from_bool (i == lines_per_page.size () - 1);
-      SCM rag = scm_from_bool (ragged () || (to_boolean (last)
-                                            && ragged_last ()));
+      bool partbook_last_page = (i == lines_per_page.size () - 1);
+      SCM rag = scm_from_bool (ragged () || ( partbook_last_page && ragged_last ()));
       SCM line_count = scm_from_int (lines_per_page[i]);
       SCM lines = scm_list_head (systems, line_count);
       SCM page = scm_apply_0 (make_page,
-                             scm_list_n (book, lines, page_num,
-                                         rag, last, SCM_UNDEFINED));
-
+                             scm_list_n (book, lines, page_num, rag,
+                                         scm_from_bool (last_bookpart),
+                                         scm_from_bool (partbook_last_page),
+                                         SCM_UNDEFINED));
       /* collect labels */
       for (SCM l = lines ; scm_is_pair (l)  ; l = scm_cdr (l))
        {
@@ -290,7 +295,7 @@ Page_breaking::make_pages (vector<vsize> lines_per_page, SCM systems)
       ret = scm_cons (page, ret);
       systems = scm_list_tail (systems, line_count);
     }
-  book_->paper_->set_variable (ly_symbol2scm ("label-page-table"), label_page_table);
+  book_->top_paper ()->set_variable (ly_symbol2scm ("label-page-table"), label_page_table);
   ret = scm_reverse (ret);
   return ret;
 }
index 275e3ced535073f083ecb470d4e40882b4d5555f..d9832e4c0e2dd47b0e0cd17aad2aa812a48a03ec 100644 (file)
@@ -20,12 +20,16 @@ LY_DEFINE (ly_paper_book_pages, "ly:paper-book-pages",
 
 LY_DEFINE (ly_paper_book_scopes, "ly:paper-book-scopes",
           1, 0, 0, (SCM book),
-          "Return pages in layout book @var{book}.")
+          "Return scopes in layout book @var{book}.")
 {
   LY_ASSERT_SMOB (Paper_book, book, 1);
   Paper_book *pb = unsmob_paper_book (book);
 
   SCM scopes = SCM_EOL;
+  if (pb->parent_)
+    {
+      scopes = ly_paper_book_scopes (pb->parent_->self_scm ());
+    }
   if (ly_is_module (pb->header_))
     scopes = scm_cons (pb->header_, scopes);
 
index 020c2e7b21248722977acd93f0885a4ac5ef876e..069fca16fdffd7dda201455d363e075caeca071b 100644 (file)
@@ -27,10 +27,12 @@ Paper_book::Paper_book ()
   header_0_ = SCM_EOL;
   pages_ = SCM_BOOL_F;
   scores_ = SCM_EOL;
+  bookparts_ = SCM_EOL;
   performances_ = SCM_EOL;
   systems_ = SCM_BOOL_F;
 
   paper_ = 0;
+  parent_ = 0;
   smobify_self ();
 }
 
@@ -48,11 +50,14 @@ Paper_book::mark_smob (SCM smob)
   Paper_book *b = (Paper_book *) SCM_CELL_WORD_1 (smob);
   if (b->paper_)
     scm_gc_mark (b->paper_->self_scm ());
+  if (b->parent_)
+    scm_gc_mark (b->parent_->self_scm ());
   scm_gc_mark (b->header_);
   scm_gc_mark (b->header_0_);
   scm_gc_mark (b->pages_);
   scm_gc_mark (b->performances_);
   scm_gc_mark (b->scores_);
+  scm_gc_mark (b->bookparts_);
   return b->systems_;
 }
 
@@ -65,6 +70,15 @@ Paper_book::print_smob (SCM smob, SCM port, scm_print_state*)
   return 1;
 }
 
+Output_def *
+Paper_book::top_paper ()
+{
+  Output_def *paper = paper_;
+  while (paper->parent_)
+    paper = paper->parent_;
+  return paper;
+}
+
 SCM
 dump_fields ()
 {
@@ -82,6 +96,12 @@ Paper_book::add_score (SCM s)
   scores_ = scm_cons (s, scores_);
 }
 
+void
+Paper_book::add_bookpart (SCM p)
+{
+  bookparts_ = scm_cons (p, bookparts_);
+}
+
 void
 Paper_book::add_performance (SCM s)
 {
@@ -89,20 +109,56 @@ Paper_book::add_performance (SCM s)
 }
 
 void
-Paper_book::output (SCM output_channel)
+Paper_book::output_aux (SCM output_channel,
+                       bool is_last,
+                       int *first_page_number,
+                       int *first_performance_number)
 {
   if (scm_is_pair (performances_))
     {
       SCM proc = ly_lily_module_constant ("write-performances-midis");
  
-      scm_call_2 (proc, performances (), output_channel);
+      scm_call_3 (proc,
+                 performances (),
+                 output_channel,
+                 scm_long2num (*first_performance_number));
+      *first_performance_number += scm_ilength (performances_);
     }
 
-  if (scores_ == SCM_EOL)
-    return;
+  if (scm_is_pair (bookparts_))
+    {
+      for (SCM p = scm_reverse (bookparts_); scm_is_pair (p); p = scm_cdr (p))
+       if (Paper_book *pbookpart = unsmob_paper_book (scm_car (p)))
+         {
+           bool is_last_part = (is_last && !scm_is_pair (scm_cdr (p)));
+           pbookpart->output_aux (output_channel,
+                                  is_last_part,
+                                  first_page_number,
+                                  first_performance_number);
+         }
+    }
+  else
+    {
+      if (scores_ == SCM_EOL)
+       return;
+      paper_->set_variable (ly_symbol2scm ("first-page-number"),
+                           scm_long2num (*first_page_number));
+      paper_->set_variable (ly_symbol2scm ("is-last-bookpart"),
+                           ly_bool2scm (is_last));
+      /* Generate all stencils to trigger font loads.  */
+      *first_page_number += scm_ilength (pages ());
+    }
+}
 
-  /* Generate all stencils to trigger font loads.  */
-  pages ();
+void
+Paper_book::output (SCM output_channel)
+{
+  int first_page_number = robust_scm2int (paper_->c_variable ("first-page-number"), 1);
+  int first_performance_number = 0;
+  output_aux (output_channel,
+             true,
+             &first_page_number,
+             &first_performance_number);
 
   SCM scopes = SCM_EOL;
   if (ly_is_module (header_))
@@ -137,17 +193,28 @@ Paper_book::output (SCM output_channel)
 }
 
 void
-Paper_book::classic_output (SCM output)
+Paper_book::classic_output_aux (SCM output,
+                               int *first_performance_number)
 {
   if (scm_is_pair (performances_))
     {
       SCM proc = ly_lily_module_constant ("write-performances-midis");
-      scm_call_2 (proc, performances (), output);
+      scm_call_3 (proc,
+                 performances (),
+                 output,
+                 scm_long2num (*first_performance_number));
+      *first_performance_number += scm_ilength (performances_);
     }
   
   /* Generate all stencils to trigger font loads.  */
   systems ();
+}
+
+void
+Paper_book::classic_output (SCM output)
+{
+  int first_performance_number = 0;
+  classic_output_aux (output, &first_performance_number);
 
   SCM scopes = SCM_EOL;
   if (ly_is_module (header_))
@@ -328,7 +395,7 @@ Paper_book::get_system_specs ()
       SCM props = paper_->lookup_variable (ly_symbol2scm ("book-title-properties"));
       Prob *ps = make_paper_system (props);
       paper_system_set_stencil (ps, title);
-
+      
       system_specs = scm_cons (ps->self_scm (), system_specs);
       ps->unprotect ();
     }
@@ -448,45 +515,53 @@ Paper_book::systems ()
     return systems_;
 
   systems_ = SCM_EOL;
-  SCM specs = get_system_specs ();
-  for (SCM s = specs; scm_is_pair (s); s = scm_cdr (s))
+  if (scm_is_pair (bookparts_))
     {
-      if (Paper_score *pscore = dynamic_cast<Paper_score*> (unsmob_music_output (scm_car (s))))
-       {
-         SCM system_list = scm_vector_to_list (pscore->get_paper_systems ());
-         system_list = scm_reverse (system_list);
-         systems_ = scm_append (scm_list_2 (system_list, systems_));
-       }
-      else
-       {
-         systems_ = scm_cons (scm_car (s), systems_);
-       }
+      for (SCM p = scm_reverse (bookparts_); scm_is_pair (p); p = scm_cdr (p))
+       if (Paper_book *pbookpart = unsmob_paper_book (scm_car (p)))
+         systems_ = scm_append_x (scm_list_2 (systems_, pbookpart->systems ()));
     }
-  
-  systems_ = scm_reverse (systems_);
-
-  /* backwards compatibility for the old page breaker */
-  int i = 0;
-  Prob *last = 0;
-  for (SCM s = systems_; scm_is_pair (s); s = scm_cdr (s))
+  else
     {
-      Prob *ps = unsmob_prob (scm_car (s));
-      ps->set_property ("number", scm_from_int (++i));
-
-      if (last
-         && to_boolean (last->get_property ("is-title"))
-         && !scm_is_number (ps->get_property ("penalty")))
-       ps->set_property ("penalty", scm_from_int (10000));
-      last = ps;
+      SCM specs = get_system_specs ();
+      for (SCM s = specs; scm_is_pair (s); s = scm_cdr (s))
+       {
+         if (Paper_score *pscore = dynamic_cast<Paper_score*> (unsmob_music_output (scm_car (s))))
+           {
+             SCM system_list = scm_vector_to_list (pscore->get_paper_systems ());
+             system_list = scm_reverse (system_list);
+             systems_ = scm_append (scm_list_2 (system_list, systems_));
+           }
+         else
+           {
+             systems_ = scm_cons (scm_car (s), systems_);
+           }
+       }
+      systems_ = scm_reverse (systems_);
 
-      if (scm_is_pair (scm_cdr (s)))
+      /* backwards compatibility for the old page breaker */
+      int i = 0;
+      Prob *last = 0;
+      for (SCM s = systems_; scm_is_pair (s); s = scm_cdr (s))
        {
-         SCM perm = ps->get_property ("page-break-permission");
-         Prob *next = unsmob_prob (scm_cadr (s));
-         if (perm == SCM_EOL)
-           next->set_property ("penalty", scm_from_int (10001));
-         else if (perm == ly_symbol2scm ("force"))
-           next->set_property ("penalty", scm_from_int (-10001));
+         Prob *ps = unsmob_prob (scm_car (s));
+         ps->set_property ("number", scm_from_int (++i));
+         
+         if (last
+             && to_boolean (last->get_property ("is-title"))
+             && !scm_is_number (ps->get_property ("penalty")))
+           ps->set_property ("penalty", scm_from_int (10000));
+         last = ps;
+         
+         if (scm_is_pair (scm_cdr (s)))
+           {
+             SCM perm = ps->get_property ("page-break-permission");
+             Prob *next = unsmob_prob (scm_cadr (s));
+             if (perm == SCM_EOL)
+               next->set_property ("penalty", scm_from_int (10001));
+             else if (perm == ly_symbol2scm ("force"))
+               next->set_property ("penalty", scm_from_int (-10001));
+           }
        }
     }
 
@@ -500,22 +575,29 @@ Paper_book::pages ()
     return pages_;
 
   pages_ = SCM_EOL;
-  SCM proc = paper_->c_variable ("page-breaking-wrapper");
-  pages_ = scm_apply_0 (proc, scm_list_1 (self_scm ()));
-
-  /* set systems_ from the pages */
-  if (systems_ == SCM_BOOL_F)
+  if (scm_is_pair (bookparts_))
     {
-      systems_ = SCM_EOL;
-      for (SCM p = pages_; scm_is_pair (p); p = scm_cdr (p))
-       {
-         Prob *page = unsmob_prob (scm_car (p));
-         SCM systems = page->get_property ("lines");
+      for (SCM p = scm_reverse (bookparts_); scm_is_pair (p); p = scm_cdr (p))
+       if (Paper_book *pbookpart = unsmob_paper_book (scm_car (p)))
+         pages_ = scm_append_x (scm_list_2 (pages_, pbookpart->pages ()));
+    }
+  else
+    {
+      SCM proc = paper_->c_variable ("page-breaking-wrapper");
+      pages_ = scm_apply_0 (proc, scm_list_1 (self_scm ()));
 
-         systems_ = scm_append (scm_list_2 (systems_, systems));
+      /* set systems_ from the pages */
+      if (systems_ == SCM_BOOL_F)
+       {
+         systems_ = SCM_EOL;
+         for (SCM p = pages_; scm_is_pair (p); p = scm_cdr (p))
+           {
+             Prob *page = unsmob_prob (scm_car (p));
+             SCM systems = page->get_property ("lines");
+             systems_ = scm_append (scm_list_2 (systems_, systems));
+           }
        }
     }
-
   return pages_;
 }
 
index be4e7e26e521cba2ff39792d7c14dcd8b475f0d8..2e0887f954f806f2ee1ebedadf1a6b002d844a49 100644 (file)
@@ -159,6 +159,7 @@ void set_music_properties (Music *p, SCM a);
 %token ALIAS "\\alias"
 %token ALTERNATIVE "\\alternative"
 %token BOOK "\\book"
+%token BOOKPART "\\bookpart"
 %token CHANGE "\\change"
 %token CHORDMODE "\\chordmode"
 %token CHORDS "\\chords"
@@ -306,6 +307,8 @@ If we give names, Bison complains.
 
 %type <book> book_block
 %type <book> book_body
+%type <book> bookpart_block
+%type <book> bookpart_body
 
 %type <i> bare_unsigned
 %type <scm> figured_bass_alteration
@@ -474,6 +477,12 @@ toplevel_expression:
                scm_call_2 (proc, PARSER->self_scm (), book->self_scm ());
                book->unprotect ();
        }
+       | bookpart_block {
+               Book *bookpart = $1;
+               SCM proc = PARSER->lexer_->lookup_identifier ("toplevel-bookpart-handler");
+               scm_call_2 (proc, PARSER->self_scm (), bookpart->self_scm ());
+               bookpart->unprotect ();
+       }
        | score_block {
                Score *score = $1;
                
@@ -565,6 +574,10 @@ identifier_init:
                $$ = $1->self_scm ();
                $1->unprotect ();
        }
+       | bookpart_block {
+               $$ = $1->self_scm ();
+               $1->unprotect ();
+       }
        | output_def {
                $$ = $1->self_scm ();
                $1->unprotect ();
@@ -641,6 +654,7 @@ context_def_spec_body:
 book_block:
        BOOK '{' book_body '}'  {
                $$ = $3;
+               unstack_paper (PARSER);
        }
        ;
 
@@ -653,6 +667,7 @@ book_body:
                $$->origin ()->set_spot (@$);
                $$->paper_ = dynamic_cast<Output_def*> (unsmob_output_def (PARSER->lexer_->lookup_identifier ("$defaultpaper"))->clone ());
                $$->paper_->unprotect ();
+               stack_paper (PARSER, $$->paper_);
                $$->header_ = PARSER->lexer_->lookup_identifier ("$defaultheader"); 
        }
        | BOOK_IDENTIFIER {
@@ -663,6 +678,13 @@ book_body:
        | book_body paper_block {
                $$->paper_ = $2;
                $2->unprotect ();
+               set_paper (PARSER, $2);
+       }
+       | book_body bookpart_block {
+               Book *bookpart = $2;
+               SCM proc = PARSER->lexer_->lookup_identifier ("book-bookpart-handler");
+               scm_call_2 (proc, $$->self_scm (), bookpart->self_scm ());
+               bookpart->unprotect ();
        }
        | book_body score_block {
                Score *score = $2;
@@ -689,12 +711,64 @@ book_body:
        | book_body error {
                $$->paper_ = 0;
                $$->scores_ = SCM_EOL;
+               $$->bookparts_ = SCM_EOL;
        }
        | book_body object_id_setting {
                $$->user_key_ = ly_scm2string ($2);
        }
        ;
 
+bookpart_block:
+       BOOKPART '{' bookpart_body '}' {
+               $$ = $3;
+       }
+       ;
+
+bookpart_body:
+       {
+               $$ = new Book;
+               $$->origin ()->set_spot (@$);
+       }
+       | BOOK_IDENTIFIER {
+               $$ = unsmob_book ($1);
+               $$->protect ();
+               $$->origin ()->set_spot (@$);
+       }
+       | bookpart_body paper_block {
+               $$->paper_ = $2;
+               $2->unprotect ();
+       }
+       | bookpart_body score_block {
+               Score *score = $2;
+               SCM proc = PARSER->lexer_->lookup_identifier ("bookpart-score-handler");
+               scm_call_2 (proc, $$->self_scm (), score->self_scm ());
+               score->unprotect ();
+       }
+       | bookpart_body composite_music {
+               Music *music = unsmob_music ($2);
+               SCM proc = PARSER->lexer_->lookup_identifier ("bookpart-music-handler");
+               scm_call_3 (proc, PARSER->self_scm (), $$->self_scm (), music->self_scm ());
+       }
+       | bookpart_body full_markup {
+               SCM proc = PARSER->lexer_->lookup_identifier ("bookpart-text-handler");
+               scm_call_2 (proc, $$->self_scm (), scm_list_1 ($2));
+       }
+       | bookpart_body full_markup_list {
+               SCM proc = PARSER->lexer_->lookup_identifier ("bookpart-text-handler");
+               scm_call_2 (proc, $$->self_scm (), $2);
+       }
+       | bookpart_body lilypond_header {
+               $$->header_ = $2;
+       }
+       | bookpart_body error {
+               $$->paper_ = 0;
+               $$->scores_ = SCM_EOL;
+       }
+       | bookpart_body object_id_setting {
+               $$->user_key_ = ly_scm2string ($2);
+       }
+       ;
+
 score_block:
        SCORE '{' score_body '}'        {
                $$ = $3;
index 661c7f88546afd9f19af5c584bee11998adeeab3..2e2f46ecb62891f46391d0727acb80923a870127 100644 (file)
@@ -111,13 +111,18 @@ setDefaultDurationToQuarter = { c4 }
 #(define musicQuotes (make-hash-table 29))
 
 #(define toplevel-book-handler print-book-with-defaults)
+#(define toplevel-bookpart-handler collect-bookpart-for-book)
 #(define toplevel-music-handler collect-music-for-book)
 #(define toplevel-score-handler collect-scores-for-book)
 #(define toplevel-text-handler collect-scores-for-book)
 
+#(define book-bookpart-handler ly:book-add-bookpart!)
 #(define book-music-handler collect-book-music-for-book)
 #(define book-score-handler ly:book-add-score!)
 #(define book-text-handler ly:book-add-score!)
 
+#(define bookpart-score-handler ly:book-add-score!)
+#(define bookpart-text-handler ly:book-add-score!)
+#(define bookpart-music-handler collect-book-music-for-book)
 
 \include "predefined-fretboards-init.ly"
index a4bd1c3a3985a466f1c888ac2a58e30197739ae8..5a2103e83c4a47822fad73649b43e143bfda1589 100644 (file)
@@ -10,7 +10,8 @@
 
 
 #(ly:set-option 'old-relative #f)
-#(define toplevel-scores '())
+#(define toplevel-scores (list))
+#(define toplevel-bookparts (list))
 #(define output-count 0) 
 #(define $defaultheader #f)
 #(define version-seen #f)
   (version-not-seen-message input-file-name))
 
 #(ly:set-option 'protected-scheme-parsing #f)
-#(if (or (pair? toplevel-scores) output-empty-score-list)
-  ((if (defined? 'default-toplevel-book-handler)
-    default-toplevel-book-handler
-    toplevel-book-handler)
-   parser
-   (apply ly:make-book $defaultpaper $defaultheader toplevel-scores)))
 
+#(let ((book-handler (if (defined? 'default-toplevel-book-handler)
+                         default-toplevel-book-handler
+                         toplevel-book-handler)))
+   (cond ((pair? toplevel-bookparts)
+          (let ((book (ly:make-book $defaultpaper $defaultheader)))
+            (map (lambda (part)
+                   (ly:book-add-bookpart! book part))
+                 (reverse! toplevel-bookparts))
+            (set! toplevel-bookparts (list))
+            ;; if scores have been defined after the last explicit \bookpart:
+            (if (pair? toplevel-scores)
+                (map (lambda (score)
+                       (ly:book-add-score! book score))
+                     (reverse! toplevel-scores)))
+            (set! toplevel-scores (list))
+            (book-handler parser book)))
+         ((or (pair? toplevel-scores) output-empty-score-list)
+          (book-handler parser (apply ly:make-book $defaultpaper
+                                      $defaultheader toplevel-scores)))))
 
 #(if (eq? expect-error (ly:parser-has-error? parser))
   (ly:parser-clear-error parser)
index 9ef8cd48dd9b598f6d8f8a216474c6e117518781..08b23d469d8538c99d6538502d8aa8a14e7489a3 100644 (file)
@@ -69,22 +69,48 @@ scoreTitleMarkup = \markup { \column {
 }
 }
 
+%% Book first page and last page predicates
 #(define (first-page layout props arg)
+  (define (ancestor layout)
+    "Return the topmost layout ancestor"
+    (let ((parent (ly:output-def-parent layout)))
+       (if (not (ly:output-def? parent))
+           layout
+           (ancestor parent))))
   (if (= (chain-assoc-get 'page:page-number props -1)
-         (ly:output-def-lookup layout 'first-page-number))
+         (ly:output-def-lookup (ancestor layout) 'first-page-number))
       (interpret-markup layout props arg)
       empty-stencil))
 
 #(define (last-page layout props arg)
-  (if (chain-assoc-get 'page:last? props #f)
-   (interpret-markup layout props arg)
-   empty-stencil))
+  (if (and (chain-assoc-get 'page:is-bookpart-last-page props #f)
+           (chain-assoc-get 'page:is-last-bookpart props #f))
+      (interpret-markup layout props arg)
+      empty-stencil))
 
 #(define (not-first-page layout props arg)
+  (define (ancestor layout)
+    "Return the topmost layout ancestor"
+    (let ((parent (ly:output-def-parent layout)))
+       (if (not (ly:output-def? parent))
+           layout
+           (ancestor parent))))
   (if (not (= (chain-assoc-get 'page:page-number props -1)
-              (ly:output-def-lookup layout 'first-page-number)))
-   (interpret-markup layout props arg)
-   empty-stencil))
+              (ly:output-def-lookup (ancestor layout) 'first-page-number)))
+      (interpret-markup layout props arg)
+      empty-stencil))
+
+%% Bookpart first page and last page predicates
+#(define (part-first-page layout props arg)
+  (if (= (chain-assoc-get 'page:page-number props -1)
+         (ly:output-def-lookup layout 'first-page-number))
+      (interpret-markup layout props arg)
+      empty-stencil))
+
+#(define (part-last-page layout props arg)
+  (if (chain-assoc-get 'page:is-bookpart-last-page props #f)
+      (interpret-markup layout props arg)
+      empty-stencil))
 
 %% unused
 #(define (not-single-page layout props arg)
index 1686d9613a11d7ac097e484f797f462282feb372..00add35806bf2f9bd3b069c50589cfee9b46cdf7 100644 (file)
@@ -31,7 +31,8 @@
             (= (interval-start system-extent)
                (interval-end   system-extent))))))
 
-(define (stretch-and-draw-page paper-book systems page-number ragged last)
+(define (stretch-and-draw-page paper-book systems page-number ragged
+                               is-last-bookpart is-bookpart-last-page)
   (define (max-stretch sys)
     (if (ly:grob? sys)
        (ly:grob-property sys 'max-stretch)
@@ -78,7 +79,8 @@
 
   (let* ((page (make-page paper-book
                          'page-number page-number
-                         'is-last last))
+                         'is-last-bookpart is-last-bookpart
+                         'is-bookpart-last-page is-bookpart-last-page))
         (paper (ly:paper-book-paper paper-book))
         (height (page-printable-height page))
         ; there is a certain amount of impreciseness going on here:
@@ -351,8 +353,8 @@ is what have collected so far, and has ascending page numbers."
                                       inter-system-space))
        user)))
 
-(define (walk-paths done-lines best-paths current-lines last current-best
-                   paper-book page-alist)
+(define (walk-paths done-lines best-paths current-lines is-last-bookpart
+                   is-bookpart-last-page current-best paper-book page-alist)
   "Return the best optimal-page-break-node that contains
 CURRENT-LINES. DONE-LINES.reversed ++ CURRENT-LINES is a consecutive
 ascending range of lines, and BEST-PATHS contains the optimal breaks
@@ -362,18 +364,19 @@ CURRENT-BEST is the best result sofar, or #f."
   (let* ((paper (ly:paper-book-paper paper-book))
         (this-page (make-page
                     paper-book
-                    'is-last last
+                    'is-last-bookpart is-last-bookpart
+                    'is-bookpart-last-page is-bookpart-last-page
                     'page-number (if (null? best-paths)
                                      (ly:output-def-lookup paper 'first-page-number)
                                      (1+ (page-page-number (first best-paths))))))
         (ragged-all (eq? #t (ly:output-def-lookup paper 'ragged-bottom)))
         (ragged-last (eq? #t (ly:output-def-lookup paper 'ragged-last-bottom)))
-        (ragged (or ragged-all (and ragged-last last)))
+        (ragged (or ragged-all (and ragged-last is-bookpart-last-page)))
         (space-to-fill (page-maximum-space-to-fill this-page current-lines paper))
         (vertical-spacing (space-systems space-to-fill current-lines ragged paper #f))
         (satisfied-constraints (car vertical-spacing))
         (force (if satisfied-constraints
-                   (if (and last ragged-last)
+                   (if (and is-bookpart-last-page ragged-last)
                        0.0
                        satisfied-constraints)
                    10000))
@@ -411,7 +414,7 @@ CURRENT-BEST is the best result sofar, or #f."
         (list
          "\nuser pen " user-penalty
          "\nsatisfied-constraints" satisfied-constraints
-         "\nlast? " last "ragged?" ragged
+         "\nlast? " is-bookpart-last-page "ragged?" ragged
          "\nis-better " is-better " total-penalty " total-penalty "\n"
          "\nconfig " positions
          "\nforce " force
@@ -427,11 +430,11 @@ CURRENT-BEST is the best result sofar, or #f."
             satisfied-constraints)
        (walk-paths (cdr done-lines) (cdr best-paths)
                    (cons (car done-lines) current-lines)
-                   last new-best
+                   is-last-bookpart is-bookpart-last-page new-best
                    paper-book page-alist)
        new-best)))
 
-(define (walk-lines done best-paths todo paper-book page-alist)
+(define (walk-lines done best-paths todo paper-book page-alist is-last-bookpart)
   "Return the best page breaking as a single
 page node for optimally breaking TODO ++
 DONE.reversed. BEST-PATHS is a list of break nodes corresponding to
@@ -439,14 +442,15 @@ DONE."
   (if (null? todo)
       (car best-paths)
       (let* ((this-line (car todo))
-            (last (null? (cdr todo)))
-            (next (walk-paths done best-paths (list this-line) last #f
-                              paper-book page-alist)))
+            (is-bookpart-last-page (null? (cdr todo)))
+            (next (walk-paths done best-paths (list this-line) is-last-bookpart
+                              is-bookpart-last-page #f paper-book page-alist)))
        (walk-lines (cons this-line done)
                    (cons next best-paths)
                    (cdr todo)
                    paper-book
-                   page-alist))))
+                   page-alist
+                   is-last-bookpart))))
 
 (define-public (optimal-page-breaks paper-book)
   "Return pages as a list starting with 1st page. Each page is a 'page Prob."
@@ -454,11 +458,11 @@ DONE."
         (lines (ly:paper-book-systems paper-book))
         (page-alist (layout->page-init paper)) 
         (force-equalization-factor (ly:output-def-lookup
-                                    paper 'verticalequalizationfactor 0.3)))
+                                    paper 'verticalequalizationfactor 0.3))
+         (is-last-bookpart (ly:output-def-lookup paper 'is-last-bookpart)))
     (ly:message (_ "Calculating page breaks..."))
-    (let* ((best-break-node (walk-lines '() '() lines paper-book page-alist))
+    (let* ((best-break-node (walk-lines '() '() lines paper-book page-alist is-last-bookpart))
           (break-nodes (get-path best-break-node '())))
-      (page-set-property! (car (last-pair break-nodes)) 'is-last #t)
       (if #f; (ly:get-option 'verbose)
          (begin
            (display (list
index f772d0527e931efa53cdf0917fcf359012e911bb..58c8720d84421e8693b8b8e42c49b82a46d1d5dd 100644 (file)
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; parser <-> output hooks.
-
                
+(define-public (collect-bookpart-for-book parser book-part)
+  "Toplevel book-part handler"
+  (define (add-bookpart book-part)
+    (ly:parser-define!
+       parser 'toplevel-bookparts
+       (cons book-part (ly:parser-lookup parser 'toplevel-bookparts))))
+  ;; If toplevel scores have been found before this \bookpart,
+  ;; add them first to a dedicated bookpart
+  (if (pair? (ly:parser-lookup parser 'toplevel-scores))
+      (begin
+       (add-bookpart (ly:make-book-part
+                      (ly:parser-lookup parser 'toplevel-scores)))
+       (ly:parser-define! parser 'toplevel-scores (list))))
+  (add-bookpart book-part))
+
 (define-public (collect-scores-for-book parser score)
   (ly:parser-define!
    parser 'toplevel-scores
    (cons score (ly:parser-lookup parser 'toplevel-scores))))
 
-(define (collect-music-aux score-handler parser music)
+(define-public (collect-music-aux score-handler parser music)
   (define (music-property symbol)
     (let ((value (ly:music-property music symbol)))
       (if (not (null? value))
index 5d3277d820095e2c4deca9cd5ebc76bbd53c83a3..a5c1bd338d9450f12b858ec49b9095e13e7e53de 100644 (file)
@@ -284,14 +284,12 @@ returns the program of the instrument
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;
 
-(define-public (write-performances-midis performances basename)
+(define-public (write-performances-midis performances basename . rest)
   (let ((midi-ext (ly:get-option 'midi-extension)))
     (let
        loop
       ((perfs performances)
-       (count 0))
-
-
+       (count (if (null? rest) 0 (car rest))))
       (if (pair?  perfs)
          (begin
            (ly:performance-write
index 3e25bdaaee3b46059ce22a90eb1578cb8b7b6426..5e2764100a9b4a507ffb002d9dd2bee2b4704ac9 100644 (file)
 \f
 
 
-(define (page-headfoot layout scopes number
-                      sym separation-symbol dir last?)
+(define (page-headfoot layout scopes number sym separation-symbol dir
+                      is-last-bookpart is-bookpart-last-page)
   
   "Create a stencil including separating space."
 
         (stencil (ly:make-stencil "" '(0 . 0) '(0 . 0)))
         (head-stencil
          (if (procedure? header-proc)
-             (header-proc layout scopes number last?)
-             #f))
-        )
+             (header-proc layout scopes number is-last-bookpart is-bookpart-last-page)
+             #f)))
     
     (if (and (number? sep)
             (ly:stencil? head-stencil)
        (layout (ly:paper-book-paper paper-book))
        (scopes (ly:paper-book-scopes paper-book))
        (number (page-page-number page))
-       (last? (page-property page 'is-last))
-       )
+       (is-last-bookpart (page-property page 'is-last-bookpart))
+       (is-bookpart-last-page (page-property page 'is-bookpart-last-page)))
        
       (page-headfoot layout scopes number
                (if (= dir UP)
                (if (= dir UP)
                    'head-separation
                    'foot-separation)
-               dir last?)))
+               dir is-last-bookpart is-bookpart-last-page)))
 
 (define (page-header page)
   (page-header-or-footer page UP))
index 23fdce87752f5415d1f6d4626c7e6df7d061219a..1ab08d73b7797422e94d55daa34dedf240bd25a8 100644 (file)
 
 ;;;;;;;;;;;;;;;;;;
 
-(define-public ((marked-up-headfoot what-odd what-even) layout scopes page-number last?)
+(define-public ((marked-up-headfoot what-odd what-even)
+                layout scopes page-number is-last-bookpart is-bookpart-last-page)
 
   "Read variables WHAT-ODD, WHAT-EVEN from LAYOUT, and interpret them
 as markup. The PROPS argument will include variables set in SCOPES and
-page:last?, page:page-number-string and page:page-number
-" 
+page:is-bookpart-last-page, page:is-last-bookpart, page:page-number-string
+and page:page-number
 
   (define (get sym)
     (ly:output-def-lookup layout sym))
@@ -41,7 +42,8 @@ page:last?, page:page-number-string and page:page-number
                 (cons 'header:tagline
                       (ly:modules-lookup scopes 'tagline
                                          (ly:output-def-lookup layout 'tagline)))
-                (cons 'page:last? last?)
+                (cons 'page:is-last-bookpart is-last-bookpart)
+                (cons 'page:is-bookpart-last-page is-bookpart-last-page)
                 (cons 'page:page-number-string
                       (number->string page-number))
                 (cons 'page:page-number page-number)))
@@ -49,7 +51,6 @@ page:last?, page:page-number-string and page:page-number
                       (list pgnum-alist)
                       prefixed-alists
                       (layout-extract-page-properties layout))))
-         
          (interpret-markup layout props potential-markup))
 
        empty-stencil))