lilypond-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Custom footers


From: Thomas Morley
Subject: Re: Custom footers
Date: Sun, 24 Mar 2013 19:48:00 +0100

2013/3/20 Jérôme Plût <address@hidden>:
> Decimo tertio Kalendas Apriles MMXIII scripsit Thomas Morley :

>> Though, I didn't manage to code "(1/3)" for consecutive bookparts,
>> because I didn't understand how to get or calculate the
>> bookpart-last-page-number.
>
> The simplest way to do it would be the TeX way: saving the page count
> for each section in a .aux file and reading this again on second
> compilation. Unless, of course, the (open) Scheme function is disabled
> in Lilypond. I will have a try at this.

Hi Jérôme,

following this approach I come up with the code below.

The book will be processed two times (ofcourse this will nearly double
compilation-time). The first run will be deleted.
Some more comments and TODOs in the code.



\version "2.16.2"
%\version "2.12.3"

%% Needed to get the all definitions from /ly/titling-init.ly to predefine
%% different footers.
\include "titling-init.ly"

#(define (looking-up layout props symbol)
   (define (ancestor layout)
     "Return the topmost layout ancestor"
     (let ((parent (ly:output-def-parent layout)))
       (if (not (ly:output-def? parent))
           layout
           (ancestor parent))))
   (ly:output-def-lookup (ancestor layout) symbol))

#(define (book-second-page? layout props)
   "Return #t iff the current page number, got from @code{props}, is the
    book second one."
   (= (chain-assoc-get 'page:page-number props -1)
      (+ (looking-up layout props 'first-page-number) 1)))

#(define (not-second-page layout props arg)
   (if (not (book-second-page? layout props))
       (interpret-markup layout props arg)
       empty-stencil))

#(define (print-bookpart-numbers layout props arg)
 "The title says it all."
   (let* ((book-page-number
            (chain-assoc-get 'page:page-number props -1))
          (bookpart-first-page-number
            (ly:output-def-lookup layout 'first-page-number))
          (book-part-numbers
            (number->string (- book-page-number bookpart-first-page-number -1)))
          (book-part-number-markup
            (markup book-part-numbers)))
      (interpret-markup layout props book-part-number-markup)))

#(define (get-first-greater n l)
 "Return the first element of list l, which is greater than number n.
  l is supposed to be an ordered list of ascending numbers."
  (if (null? l)
      1
      (if (< n (car l))
          (car l)
          (get-first-greater n (cdr l)))))

%% Inserted to make it work with 2.12.3
#(define-markup-command (vspace layout props amount)
  (number?)
  "Create an invisible object taking up vertical space
   of @var{amount} multiplied by 3."
   (let ((amount (* amount 3.0)))
     (ly:make-stencil "" (cons 0 0) (cons 0 amount))))

#(define list-of-bookpart-last-pages '())

#(define-markup-command (print-bookpart-last-page-number layout props)()
 "The title says it all."
  (let* ((part-first-page-number
           (ly:output-def-lookup layout 'first-page-number))
         (greater-than-part-first-page-number
           (get-first-greater
              ;; hackish trick to avoid wrongly taken numbers, in case the
              ;; bookpart contains only one page.
              (- part-first-page-number 0.1)
              (reverse list-of-bookpart-last-pages)))
       (last (chain-assoc-get 'page:last? props -1))
         (bookpart-last-page-number
           (- greater-than-part-first-page-number
              part-first-page-number -1)))
    (interpret-markup layout props (number->string bookpart-last-page-number))))

#(define-markup-command (make-list-of-bookpart-last-pages layout props)()
 "TODO: creating a stencil is needless, find a better method"
   (ly:make-stencil
    `(delay-stencil-evaluation
      ,(delay
         (ly:stencil-expr
           (begin
             (if (chain-assoc-get 'page:is-bookpart-last-page props #f)
                 (set! list-of-bookpart-last-pages
                       (cons (chain-assoc-get 'page:page-number props -1)
                             list-of-bookpart-last-pages)))
             (interpret-markup layout props "")))))
    '(0 . 0)
    '(0 . 0)))

myname = #(ly:parser-output-name parser)

oddFooterMarkupI =
  \markup \fill-line { "" \make-list-of-bookpart-last-pages }

oddFooterMarkupII =
   \markup {
      %% Don't print on first and second book-page
      \on-the-fly #not-first-page
      \on-the-fly #not-second-page
      \column {
        \fill-line {
          \fromproperty #'header:title
          \fontsize #2 \italic \fromproperty #'header:instrument
          %% \parenthesize or \bracket. Choose one.
          %% \parenthesize will not work here with 2.12.3
          %% Perhaps use "(" <arg> ")"
          \parenthesize
          %\bracket
          \concat {
                  \fromproperty #'header:instrument
                  "-part, page "
                  %% "" needs to be here! because
                  %% \on-the-fly expects _two_ arguments.
                  \on-the-fly #print-bookpart-numbers ""
                  "/"
                  \print-bookpart-last-page-number
          }
        }
        \fill-line {
                \concat {
                        "- page "
                        \fromproperty #'page:page-number-string
                        " -"
                }
        }
      }
    }

writeBookTwice =
#(define-void-function (parser location book)
   (ly:book?)
   "
    Processes a book in a dual pass.
    The pdf of the first run is deleted.
   "
   ;; First run of the book, processed with oddFooterMarkupI to get the
   ;; last page-number of every bookpart.
   ;; oddFooterMarkupI is added to the book-paper and every bookpart-paper.
   (map
     (lambda (bookpart)
        (ly:output-def-set-variable!
           (ly:book-paper bookpart)
           'oddFooterMarkup
           oddFooterMarkupI))
     (cons book (ly:book-book-parts book)))
   (ly:book-process
      book
      $defaultpaper
      $defaultlayout
      (format "~a-to-delete" myname))

   ;; Delete that file.
   ;; Be very careful what you delete!
   (if (file-exists? (format "~a-to-delete.pdf" myname))
       (delete-file (format "~a-to-delete.pdf" myname)))

   ;; Second run of the book, processed with oddFooterMarkupII, using the
   ;; page-numbers from the first run.
   ;; oddFooterMarkupII is added to the book-paper and every bookpart-paper.
   ;; TODO: What to do if a footer of a specific bookpart is wanted to keep?
   (map
     (lambda (bookpart)
        (ly:output-def-set-variable!
           (ly:book-paper bookpart)
           'oddFooterMarkup
           oddFooterMarkupII))
     (cons book (ly:book-book-parts book)))
   (ly:book-process
      book
      $defaultpaper
      $defaultlayout
      myname))

\writeBookTwice
\book {
  \paper {
    %% works with different settings of `first-page-number´
    %% currently the default is set
    first-page-number = 1

    %% For now page-header are set #f
    oddHeaderMarkup = ##f
    evenHeaderMarkup = ##f
  }
  \bookpart {
          \markup \column {
                \vspace #8
               \fill-line { \fontsize #12 "Music" }
               \vspace #30

               \fill-line { \override #'(span-factor . 1/3) \draw-hline }
               %% \draw-hline is not defined in "2.12.3".
               %% Use next line instead.
               %\fill-line { \postscript #"-20 0 moveto 40 0 rlineto stroke" }

               \vspace #4
               \fill-line {
                       \fontsize #1
                       \center-column {
                               "edited"
                               "by"
                               "me"
                       }
               }
          }
  }
  \bookpart {
          \markuplist \table-of-contents
          %% With 2.12.3 use:
          %\markuplines \table-of-contents
  }
  \bookpart {
          \tocItem \markup "First Piece"
          %% header on bookpart-top-level.
          %% Otherwise instrument-setting isn't recognized
          %% by page-headers/footers
          \header {
                  title = "First Piece"
                  instrument = "Trombone"
          }
          \score {
            \new Staff {
                  \repeat unfold 2 { c''1  } c''
            }
          }
  }
  \bookpart {
          %% will be overridden by \writeBookTwice
          \paper {
                  oddFooterMarkup =
                  \markup \fill-line { "xxxxxxxxxxxxxxxxxxxx" }
          }
          \tocItem \markup "Second Piece"
          \header {
                  title = "Second Piece"
                  instrument = "Saxophone"
          }
          \score {
            \new Staff {
                  \repeat unfold 3 { cis''1 \pageBreak } cis''
            }
          }
  }
  \bookpart {
          \tocItem \markup "Third Piece"
          \header {
                  title = "Third Piece"
                  instrument = "Saxophone"
          }
          \score {
            \new Staff {
                  \repeat unfold 2 { d''1 \pageBreak } d''
            }
          }
  }
  \bookpart {
          \tocItem \markup "Fourth Piece"
          \header {
                  title = "Fourth Piece"
                  instrument = "Saxophone"
          }
          \score {
            \new Staff {
                  \repeat unfold 6 { dis''1 \pageBreak } dis''
            }
          }
  }
}


Regards,
  Harm



reply via email to

[Prev in Thread] Current Thread [Next in Thread]