Header-Zeilen beeinflussen

Begonnen von rgree, Sonntag, 20. Mai 2018, 12:56

« vorheriges - nächstes »

rgree

Hallo,

ich versuche seit längerem, Lilypond dazu zu überreden,
in einer Geigen-Stimme mit mehrern Sätzen (scores) auf jeder Seite der Ausgabe
oben auszuweisen, zu welchem Satz die jeweilige Seite gehört.

Ich müsste also die Header manipulieren können im \header eines Score (mit "oddHeaderMarkup" etc.).
Da kann ich zwar was hinschreiben, aber es wird ignoriert, aber auch nicht syntaktisch abgewiesen.
Aus dem Manual lese ich heraus, dass "oddHeaderMarkup" nur auf oberster Ebene gesetzt werden können.

Eigentlich kommt die Verwendung von "piece" dem gewünschten schon sehr nahe,
aber "piece" wird nur am Anfang eines Score im Output gezeigt, nicht aber auf
Folgeseiten desselben Scores.

Was übersehe ich ?

Für Hilfe wäre ich dankbar; ein Minimalbeispiel liegt bei.
Dort soll auf Seite 4 oben erscheinen, zu welchem Satz die darunter
dargestellten Noten gehören.

Vielen Dank im Voraus.

rgree


harm6

ZitatWas übersehe ich ?

Nun weiß ich natürlich nicht was Du schon alles probiert hast, aber ich habs selber vor einiger Zeit mal versucht und habe letztlich das Handtuch geworfen.

Wenn Du etwas übersehen hast, dann hab ich das auch ...

Tut mir leid Dir nicht weiterhelfen zu können, zumindest nicht mit einer automatisierten Lösung. Du kannst das Zeug manuell einsetzen, in titiling-init.ly gibts `on-page'. Ist auch in der NR erwähnt.


Gruß,
  Harm


rgree


Malte

Ich hab gestern mal rumprobiert mit \markup \fromproperty #header:piece, aber das tat nicht so, wie ich gedacht hätte. Was ich noch nicht probiert habe: Kann man den instrument-header pro Satz ändern?

rgree

Das geht wohl nicht.

Man wäre aber fein raus, wenn man im obersten Header z.B. eine der Variablen ändern könnte a la
\set #'header:instrument = "Violine I : Satz II".
Das geht syntaktisch natürlich so nicht,
aber vielleicht gibt es eine schlaue Scheme-Prozedur,
die es erlaubt, im (obersten) Header-Puffer Variablen-Inhalte neu zu setzen.

Gruß
rgree

harm6

Ich hab' mich noch mal drangesetzt...
Aber nach wie vor keine Möglichkeit gefunden auf den score-header zuzugreifen und auf das Ergebnis zur richtigen Zeit zuzugreifen.

Insoweit ein Art workaround.
Ich setze page-marker, die eigentlich fürs Inhaltsverzeichnis gedacht sind. Lese diese Setzungen aus nachdem ich das file compiliert habe und verwende sie dann in einer zweiten Kompilation.
Ist natürlich aufwendig und funktioniert momentan nur für toplevel-Zeug. Explizite books und bookparts funktionieren nicht, stören oder verursachen einen crash.


\version "2.19.81"

%% sets page-markers for 'page-header-markup, adds it to the toc-items
tocEntryForPageHeader =
#(define-music-function (text) (markup?)
  (add-toc-item! 'page-header-markup text))
     
%% from toc-init.ly, modified to avoid printing page-header-markups in toc
#(define-markup-list-command (table-of-contents layout props) ()
  #:properties ((baseline-skip))
  ( _i "Outputs the table of contents, using the paper variable
@code{tocTitleMarkup} for its title, then the list of lines
built using the @code{tocItem} music function
Usage: @code{\\markuplist \\table-of-contents}.
@code{tocItem}s of kind 'page-header-markup are disregarded." )
  (cons (interpret-markup
          layout props (ly:output-def-lookup layout 'tocTitleMarkup))
        (space-lines
          baseline-skip
          (map
            (lambda (toc-item)
              (let ((label (car toc-item))
                    (toc-markup (cadr toc-item))
                    (text (caddr toc-item)))
                (interpret-markup
                  layout
                  (cons
                    (list
                      (cons 'toc:page
                            (markup
                              #:with-link label
                              #:page-ref label
                              "XXX" "?"))
                      (cons 'toc:text (markup #:with-link label text))
                      (cons 'toc:label label))
                    props)
                  (ly:output-def-lookup layout toc-markup))))
            ;; don't print `page-header-markup's in table-of-contents
            (remove
              (lambda (toc-item)
                (member 'page-header-markup toc-item))
            (toc-items))))))
           
%% from define-markup-commands.scm, improved
%% see https://sourceforge.net/p/testlilyissues/issues/5331/
#(define (general-column align-dir baseline mols)
  "Stack @var{mols} vertically, aligned to  @var{align-dir} horizontally.
Empty stencils are removed from @var{mols}."
  (let ((aligned-mols
          (filter-map
            (lambda (x)
              (if (ly:stencil-empty? x)
                  #f
                  (ly:stencil-aligned-to x X align-dir)))
            mols)))
    (if (pair? aligned-mols)
    (let* ((stacked-stencil (stack-lines -1 0.0 baseline aligned-mols))
               (stacked-extent (ly:stencil-extent stacked-stencil X)))
          (ly:stencil-translate-axis
            stacked-stencil (- (car stacked-extent)) X))
        empty-stencil)))
   
%% c/p from define-markup-commands.scm, to use the improved `general-align'
#(define-markup-command (center-column layout props args)
  (markup-list?)
  #:category align
  #:properties ((baseline-skip))
  "
@cindex centering a column of text

Put @code{args} in a centered column.

@lilypond[verbatim,quote]
\\markup {
  \\center-column {
    one
    two
    three
  }
}
@end lilypond"
  (general-column
    CENTER baseline-skip (interpret-markup-list layout props args)))

#(define* (get-page-header-toc-items layout pages)
"For use in the `page-post-process'-hook in paper.
Accumulates pairs of page-number and relevant toc-item.
Stores them in `lst', whoch is defined later."
  (let* ((label-table (ly:output-def-lookup layout 'label-page-table))
         (page-header-toc-items
           (filter
             (lambda (toc-item)
               (member 'page-header-markup toc-item))
           (toc-items)))
         (all-page-header-labels (map car page-header-toc-items))
         (format-line
           (lambda (toc-item)
             (let* ((label (car toc-item))
                    (text  (caddr toc-item))
                    (label-page (and (list? label-table)
                                     (assoc label label-table)))
                    (page (and label-page (cdr label-page))))
               (format #f "~a ~a" page text)
               (if (member label all-page-header-labels)
                   (cons page text)
                   #f))))
         (formatted-output
           (filter-map format-line (toc-items))))
    (if (not (null? label-table))
        (set! lst formatted-output))))

%% TODO far to expensive
%% from lily-library.scm
#(define (split-at-predicate pred lst)
  "Split LST into two lists at the first element that returns #f for
  (PRED previous_element element).  Return the two parts as a pair.
  Example: (split-at-predicate < '(1 2 3 2 1)) ==> ((1 2 3) . (2 1))"
  (let ((i (and (pair? lst)
                (list-index (lambda (x y) (not (pred x y)))
                            lst
                            (cdr lst)))))
    (if i
        (call-with-values
            (lambda () (split-at lst (1+ i)))
          cons)
        (list lst))))

#(define (trim-alist alist lst)
;; Example
;; (trim-alist
;;   '((1 . "my-first-score-A")
;;     (1 . "my-first-score-B")
;;     (2 . "my-second-score")
;;     (3 . "my-third-score-A")
;;     (3 . "my-third-score-B")
;;     (10 . "wtf-test")
;;     (10 . "wtf"))
;;   '())
;;   
;; =>
;; ((1 "my-first-score-A" "my-first-score-B")
;;  (2 "my-second-score")
;;  (3 "my-third-score-A" "my-third-score-B")
;;  (10 "wtf-test" "wtf"))

   (let ((summarized
          (split-at-predicate
            (lambda (p q) (eqv? (car p) (car q)))
            alist)))
     (if (null? (cdr summarized))
         (map
           (lambda (e)
             (cons (caar e) (map cdr e)))
           (reverse (append summarized lst)))
         (trim-alist (cdr summarized)
           (cons (car summarized) lst)))))
           
#(define ((not-on-pages strg) layout props arg)
"@var{strg} is supposed to be a comma-separated string containing numbers
or ranges like 'from-to', like @code{\"1,2-4,5,7\"}.  This string is transformed
to a number-list like @code{'(1 2 3 4 5 7)}.
For those page-numbers an empty-stencil is returned, otherwise a text-stencil
of @var{arg}."
  (let* ((page-number (chain-assoc-get 'page:page-number props -1))
         (first-step-splitted-strg (string-split strg #\,))
         (second-step-splitted-strgs
           (map
             (lambda (s)
               (if (string-contains s "-")
                   (string-split s #\-)
                   s))
             first-step-splitted-strg))
         (not-printing-at
           (append-map
             (lambda (x)
               (if (list? x)
                   (let ((range (map string->number x)))
                     (iota (1+ (- (cadr range) (car range))) (car range) 1))
                   (list (string->number x))))
             second-step-splitted-strgs)))
    (if (member page-number not-printing-at)
        empty-stencil
        (interpret-markup layout props arg))))

#(define-markup-command (on-pages layout props args)(list?)
"@var{args} is a list containing pairs with a number and a string.
If the page-number is equal or greater than this number the string will be
printed in the page-header of the relevant page."
  (if (null? args)
      empty-stencil
      (let* ((cleared-args
               (remove
                 (lambda (arg)
                   (not (number? (car arg))))
                 args))
             (page-number (chain-assoc-get 'page:page-number props -1))
             (rev-sorted-args
               (sort
                 (trim-alist cleared-args '())
                 (lambda (p q) (< (car p) (car q)))))
             (arg '())
             (numbers
               (filter-map
                 (lambda (x)
                   (if (>= page-number (car x))
                       (car x)
                       #f))
                 rev-sorted-args))
             (set-arg
               (if (and (pair? numbers) (number? (last numbers)))
                   (set! arg (assoc-get (last numbers) rev-sorted-args)))))
      (interpret-markup layout props (make-line-markup arg)))))
     
myPaper =
\paper {
  page-header-markup = " "
  #(define (page-post-process layout pages)
    (get-page-header-toc-items layout pages))
}

%% To get immediate access to the there defined procedures
\include "titling-init.ly"

myOddHeaderMarkup =
#(define-scheme-function (no-page-headers-at)(string?)
#{
  \markup
    \fill-line {
      ""
      \center-column {
       \on-the-fly #(not-on-pages no-page-headers-at)
          %\on-the-fly #not-part-first-page
            \on-pages \lst
        \on-the-fly #not-part-first-page
          \fromproperty #'header:instrument
      }
      \on-the-fly #print-page-number-check-first
        \fromproperty #'page:page-number-string
    }
#})

myEvenHeaderMarkup =
#(define-scheme-function (no-page-headers-at)(string?)
#{
  \markup
    \fill-line {
      ""
      \center-column {
        \on-the-fly #(not-on-pages no-page-headers-at)
          %\on-the-fly #not-part-first-page
            \on-pages \lst
        \on-the-fly #not-part-first-page
          \fromproperty #'header:instrument
      }
      \on-the-fly #print-page-number-check-first
        \fromproperty #'page:page-number-string
    }
#})

printIt =
#(begin
  (define lst '())
  (define-void-function (no-page-headers-at)(string?)
  ;; - make a book containing all toplevel-scores, the \paper in this step
  ;;   contains functionality to store page-markers (with page-number and
  ;;   text to print) in the extern defined `lst'
  ;; - process this book to call this functionality
  ;; - For a second run of the book:
  ;;     clear it from now unneeded `page-post-process'
  ;;     set new page-headers to access and process the stored data
  ;; - reprocess the book with the new page-headers
  ;; - avoid a third run
  ;; - with `no-page-headers-at' pages which should not get additional entries
    (let* ((book
             (apply
               ly:make-book
               myPaper
               $defaultheader
               (ly:parser-lookup 'toplevel-scores))))
       ;; first run of the book
       ;; needed to get the page-numbers how to distribute header-markuos
       (ly:book-process
         book
         $defaultpaper
         $defaultlayout
         (ly:parser-output-name))
       
       ;; clear \paper from `page-post-process', not needed for the second run
       (ly:output-def-set-variable!
          (ly:book-paper book)
          'page-post-process
          '())
         
       ;; redefine oddHeaderMarkup/evenHeaderMarkup to use the page-numbers via
       ;; `on-pages'
       (ly:output-def-set-variable!
          (ly:book-paper book)
          'oddHeaderMarkup
          (myOddHeaderMarkup no-page-headers-at))
         
       (ly:output-def-set-variable!
          (ly:book-paper book)
          'evenHeaderMarkup
          (myEvenHeaderMarkup no-page-headers-at))
         
       ;; The second run of the book with access to the page-numbers where to
       ;; place which page-header
       (ly:book-process
         book
         $defaultpaper
         $defaultlayout
         (ly:parser-output-name))
         
       ;; Avoid a third run
       (set! toplevel-scores '()))))
       
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Start of toplevel music
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     
\header {
  title = "TESTING PAGE-HEADERS"
  instrument = "Instrument"
}

\paper {
  #(set-paper-size "a5")
}

\tocItem "buzz"
\tocEntryForPageHeader "my-first-score"
\score {
  { R1 \pageBreak R1 }
  \header { piece = "xy" }
}

\pageBreak

\tocEntryForPageHeader "my-second-score"
\score {
  { R1 \pageBreak R1 \pageBreak R1 }
}

\pageBreak

\tocItem "buzzy"
\tocEntryForPageHeader "my-third-score"
\tocEntryForPageHeader "is-here"
\score {
  { R1 \pageBreak R1 }
  \header { piece = "title-3" }
}

\pageBreak

\markuplist
\table-of-contents

\pageBreak

\markup "dummy"
\pageBreak

\markup "dummy"

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% End of toplevel music
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
%% catch toplevel stuff and output a book with page-headers at appropriate
%% place
%% \book and \bookpart are not currently supported and it's usage will disturb
%% up to crash
\printIt "7-9"


Gruß,
  Harm


rgree

Wow!

Auf jeden Fall danke für deine Mühen.

Gruß,
Reinhard