Displaying typesetting information at compile time
I wonder if someone could suggest how to get LilyPond to emit various bits of information about the score it is typesetting. Specifically can it be persuaded to display the number of pages in the output PDF and the total number of systems? The idea would be to guide the user as to suitable values for \paper { system-count = xx page-count = yy } without having to count up the number of systems (pages is not really a problem of course). Richard Shann
Re: Displaying typesetting information at compile time
Le 20/03/2022 à 17:43, Richard Shann a écrit : I wonder if someone could suggest how to get LilyPond to emit various bits of information about the score it is typesetting. Specifically can it be persuaded to display the number of pages in the output PDF and the total number of systems? The idea would be to guide the user as to suitable values for \paper { system-count = xx page-count = yy } without having to count up the number of systems (pages is not really a problem of course). Richard Shann Not sure if there's a more elegant way, but you could try \version "2.22.2" markWithPageInfo = %% Must not get called before line breaking \tweak X-extent #'(0 . 0) \tweak Y-extent #'(0 . 0) \tweak horizontal-skylines #(ly:make-unpure-pure-container ly:grob::simple-horizontal-skylines-from-extents) \tweak vertical-skylines #(ly:make-unpure-pure-container ly:grob::simple-vertical-skylines-from-extents) \tweak stencil #(lambda (grob) (let* ((sys (ly:grob-system grob)) ;; No broken pieces for systems ... (alignment (ly:grob-object sys 'vertical-alignment)) (all-alignments (ly:spanner-broken-into (ly:grob-original alignment))) (all-systems (map ly:grob-system all-alignments)) (n-systems (length all-systems)) (all-pages (map (lambda (s) (ly:grob-property s 'page-number)) all-systems)) (n-pages (1+ (- (apply max all-pages) (apply min all-pages (layout (ly:grob-layout grob)) (defs (append `((n-systems . ,(number->string n-systems)) (n-pages . ,(number->string n-pages))) (ly:output-def-lookup layout 'text-font-defaults))) (props (ly:grob-alist-chain grob defs)) (text (ly:grob-property grob 'text))) (interpret-markup layout props text))) \mark \etc { \markWithPageInfo \markup { Have \fromproperty #'n-systems systems on \fromproperty #'n-pages pages } \repeat unfold 20 { 1 1 \break } } Jean
Re: Displaying typesetting information at compile time
On Sun, 2022-03-20 at 18:43 +0100, Jean Abou Samra wrote: > > \version "2.22.2" > > markWithPageInfo = > %% Must not get called before line breaking > \tweak X-extent #'(0 . 0) > \tweak Y-extent #'(0 . 0) > \tweak horizontal-skylines > #(ly:make-unpure-pure-container ly:grob::simple-horizontal- > skylines-from-extents) > \tweak vertical-skylines > #(ly:make-unpure-pure-container ly:grob::simple-vertical- > skylines-from-extents) > \tweak stencil > #(lambda (grob) > (let* ((sys (ly:grob-system grob)) > ;; No broken pieces for systems ... > (alignment (ly:grob-object sys 'vertical-alignment)) > (all-alignments (ly:spanner-broken-into (ly:grob- > original alignment))) > (all-systems (map ly:grob-system all-alignments)) > (n-systems (length all-systems)) > (all-pages (map (lambda (s) (ly:grob-property s 'page- > number)) > all-systems)) > (n-pages (1+ (- (apply max all-pages) > (apply min all-pages > (layout (ly:grob-layout grob)) > (defs (append `((n-systems . ,(number->string n- > systems)) > (n-pages . ,(number->string n-pages))) > (ly:output-def-lookup layout 'text-font- > defaults))) > (props (ly:grob-alist-chain grob defs)) > (text (ly:grob-property grob 'text))) > (interpret-markup layout props text))) > \mark \etc > > { > \markWithPageInfo \markup { Have \fromproperty #'n-systems systems > on \fromproperty #'n-pages pages } > \repeat unfold 20 { 1 1 \break } > } Wow! That goes beyond what I had in mind - it actually outputs the information within the typeset (I guess the stuff with skylining might be to avoid the typesetting of this information affecting the number of pages/systems??). What I had in mind was just some Scheme (display ...) inserted in the way Valentin (*) did with this: \override Score.SpacingSpanner.common-shortest-duration = #(grob-transformer 'common-shortest-duration (lambda (grob orig) (display orig) (newline) orig)) So that the information can be used to guide selection of tweaks. Richard (*) in the "Re: Wildly different horizontal spacing in two similar scores." thread
Re: Displaying typesetting information at compile time
Le 20/03/2022 à 19:09, Richard Shann a écrit : On Sun, 2022-03-20 at 18:43 +0100, Jean Abou Samra wrote: \version "2.22.2" markWithPageInfo = %% Must not get called before line breaking \tweak X-extent #'(0 . 0) \tweak Y-extent #'(0 . 0) \tweak horizontal-skylines #(ly:make-unpure-pure-container ly:grob::simple-horizontal- skylines-from-extents) \tweak vertical-skylines #(ly:make-unpure-pure-container ly:grob::simple-vertical- skylines-from-extents) \tweak stencil #(lambda (grob) (let* ((sys (ly:grob-system grob)) ;; No broken pieces for systems ... (alignment (ly:grob-object sys 'vertical-alignment)) (all-alignments (ly:spanner-broken-into (ly:grob- original alignment))) (all-systems (map ly:grob-system all-alignments)) (n-systems (length all-systems)) (all-pages (map (lambda (s) (ly:grob-property s 'page- number)) all-systems)) (n-pages (1+ (- (apply max all-pages) (apply min all-pages (layout (ly:grob-layout grob)) (defs (append `((n-systems . ,(number->string n- systems)) (n-pages . ,(number->string n-pages))) (ly:output-def-lookup layout 'text-font- defaults))) (props (ly:grob-alist-chain grob defs)) (text (ly:grob-property grob 'text))) (interpret-markup layout props text))) \mark \etc { \markWithPageInfo \markup { Have \fromproperty #'n-systems systems on \fromproperty #'n-pages pages } \repeat unfold 20 { 1 1 \break } } Wow! That goes beyond what I had in mind - it actually outputs the information within the typeset (I guess the stuff with skylining might be to avoid the typesetting of this information affecting the number of pages/systems??). Sort of, yes. Normally, the RehearsalMark is drawn before line breaking is done, and its width and height are accounted for during page breaking and page spacing. At that time, there is obviously no number of pages or systems available. So I'm giving it predetermined extents and skylines, which are used for page breaking and page spacing purposes, only after which the RehearsalMark's stencil is computed. The drawback is that it could collide with something on top of it. However, there was a flaw in that code. When you have several scores in a bookpart, page-count and system-count override the total numbers for the whole bookpart, but I was counting them per score. Here is a fixed version: \version "2.22.2" \paper { page-post-process = #(lambda (paper pages) (let ((n-systems 0) (page-min #f) (page-max #f)) (for-each (lambda (page) (for-each (lambda (line) (let ((sys (ly:prob-property line 'system-grob))) (if (ly:grob? sys) (let ((sys-page (ly:grob-property sys 'page-number))) (set! n-systems (1+ n-systems)) (set! page-min (if page-min (min page-min sys-page) sys-page)) (set! page-max (if page-max (max page-max sys-page) sys-page)) (ly:prob-property page 'lines))) pages) (ly:output-def-set-variable! paper 'n-systems n-systems) (ly:output-def-set-variable! paper 'n-pages (1+ (- page-max page-min) } #(define-markup-command (page-info layout props arg) (markup?) (ly:make-stencil `(delay-stencil-evaluation ,(delay (let* ((n-systems (ly:output-def-lookup layout 'n-systems)) (n-pages (ly:output-def-lookup layout 'n-pages))) (ly:stencil-expr (interpret-markup layout (cons `((n-systems . ,(number->string n-systems)) (n-pages . ,(number->string n-pages))) props) arg) '(0 . 0) '(0 . 0))) \header { subsubtitle = \markup \page-info \line { Have \fromproperty #'n-systems systems on \fromproperty #'n-pages pages } } \book { \bookpart { \repeat unfold 10 { 1 1 \break } \repeat unfold 10 { 1 1 \break } } \bookpart { \repeat unfold 20 { 1 1 \break } \repeat unfold 20 { 1 1 \break } } } Jean
Re: Displaying typesetting information at compile time
Le 21/03/2022 à 17:24, Richard Shann a écrit : On Sun, 2022-03-20 at 20:09 +0100, Jean Abou Samra wrote: Le 20/03/2022 à 19:09, Richard Shann a écrit : On Sun, 2022-03-20 at 18:43 +0100, Jean Abou Samra wrote: \version "2.22.2" markWithPageInfo = %% Must not get called before line breaking \tweak X-extent #'(0 . 0) \tweak Y-extent #'(0 . 0) \tweak horizontal-skylines #(ly:make-unpure-pure-container ly:grob::simple-horizontal- skylines-from-extents) \tweak vertical-skylines #(ly:make-unpure-pure-container ly:grob::simple-vertical- skylines-from-extents) \tweak stencil #(lambda (grob) (let* ((sys (ly:grob-system grob)) ;; No broken pieces for systems ... (alignment (ly:grob-object sys 'vertical- alignment)) (all-alignments (ly:spanner-broken-into (ly:grob- original alignment))) (all-systems (map ly:grob-system all-alignments)) (n-systems (length all-systems)) (all-pages (map (lambda (s) (ly:grob-property s 'page- number)) all-systems)) (n-pages (1+ (- (apply max all-pages) (apply min all-pages (layout (ly:grob-layout grob)) (defs (append `((n-systems . ,(number->string n- systems)) (n-pages . ,(number->string n- pages))) (ly:output-def-lookup layout 'text- font- defaults))) (props (ly:grob-alist-chain grob defs)) (text (ly:grob-property grob 'text))) (interpret-markup layout props text))) \mark \etc { \markWithPageInfo \markup { Have \fromproperty #'n-systems systems on \fromproperty #'n-pages pages } \repeat unfold 20 { 1 1 \break } } Wow! That goes beyond what I had in mind - it actually outputs the information within the typeset (I guess the stuff with skylining might be to avoid the typesetting of this information affecting the number of pages/systems??). Sort of, yes. Normally, the RehearsalMark is drawn before line breaking is done, and its width and height are accounted for during page breaking and page spacing. At that time, there is obviously no number of pages or systems available. So I'm giving it predetermined extents and skylines, which are used for page breaking and page spacing purposes, only after which the RehearsalMark's stencil is computed. The drawback is that it could collide with something on top of it. However, there was a flaw in that code. When you have several scores in a bookpart, page-count and system-count override the total numbers for the whole bookpart, but I was counting them per score. Here is a fixed version: \version "2.22.2" \paper { page-post-process = #(lambda (paper pages) (let ((n-systems 0) (page-min #f) (page-max #f)) (for-each (lambda (page) (for-each (lambda (line) (let ((sys (ly:prob-property line 'system-grob))) (if (ly:grob? sys) (let ((sys-page (ly:grob-property sys 'page- number))) (set! n-systems (1+ n-systems)) (set! page-min (if page-min (min page-min sys-page) sys-page)) (set! page-max (if page-max (max page-max sys-page) sys-page)) (ly:prob-property page 'lines))) pages) (ly:output-def-set-variable! paper 'n-systems n-systems) (ly:output-def-set-variable! paper 'n-pages (1+ (- page-max page-min) } #(define-markup-command (page-info layout props arg) (markup?) (ly:make-stencil `(delay-stencil-evaluation ,(delay (let* ((n-systems (ly:output-def-lookup layout 'n-systems)) (n-pages (ly:output-def-lookup layout 'n-pages))) (ly:stencil-expr (interpret-markup layout (cons `((n-systems . ,(number->string n-systems)) (n-pages . ,(number->string n-pages))) props) arg) '(0 . 0) '(0 . 0))) \header { subsubtitle = \markup \page-info \line { Have \fromproperty #'n-systems systems on \fromproperty #'n-pages pages } } \book { \bookpart { \repeat unfold 10 { 1 1 \break } \repeat unfold 10 { 1 1 \break } } \bookpart { \repeat unfold 20 { 1 1 \break } \repeat unfold 20 { 1 1 \break } } } Thanks again - I think I would prefer the information on the terminal though so I modified your code to do that: 8><8><8><8><8><8><8><8><8><8><8
Re: Displaying typesetting information at compile time
On Sun, 2022-03-20 at 20:09 +0100, Jean Abou Samra wrote: > > > Le 20/03/2022 à 19:09, Richard Shann a écrit : > > On Sun, 2022-03-20 at 18:43 +0100, Jean Abou Samra wrote: > > > \version "2.22.2" > > > > > > markWithPageInfo = > > > %% Must not get called before line breaking > > > \tweak X-extent #'(0 . 0) > > > \tweak Y-extent #'(0 . 0) > > > \tweak horizontal-skylines > > > #(ly:make-unpure-pure-container ly:grob::simple-horizontal- > > > skylines-from-extents) > > > \tweak vertical-skylines > > > #(ly:make-unpure-pure-container ly:grob::simple-vertical- > > > skylines-from-extents) > > > \tweak stencil > > > #(lambda (grob) > > > (let* ((sys (ly:grob-system grob)) > > > ;; No broken pieces for systems ... > > > (alignment (ly:grob-object sys 'vertical- > > > alignment)) > > > (all-alignments (ly:spanner-broken-into (ly:grob- > > > original alignment))) > > > (all-systems (map ly:grob-system all-alignments)) > > > (n-systems (length all-systems)) > > > (all-pages (map (lambda (s) (ly:grob-property s > > > 'page- > > > number)) > > > all-systems)) > > > (n-pages (1+ (- (apply max all-pages) > > > (apply min all-pages > > > (layout (ly:grob-layout grob)) > > > (defs (append `((n-systems . ,(number->string n- > > > systems)) > > > (n-pages . ,(number->string n- > > > pages))) > > > (ly:output-def-lookup layout 'text- > > > font- > > > defaults))) > > > (props (ly:grob-alist-chain grob defs)) > > > (text (ly:grob-property grob 'text))) > > > (interpret-markup layout props text))) > > > \mark \etc > > > > > > { > > > \markWithPageInfo \markup { Have \fromproperty #'n-systems > > > systems > > > on \fromproperty #'n-pages pages } > > > \repeat unfold 20 { 1 1 \break } > > > } > > Wow! That goes beyond what I had in mind - it actually outputs the > > information within the typeset (I guess the stuff with skylining > > might > > be to avoid the typesetting of this information affecting the > > number of > > pages/systems??). > > > > Sort of, yes. Normally, the RehearsalMark is drawn before line > breaking > is done, and its width and height are accounted for during page > breaking > and page spacing. At that time, there is obviously no number of pages > or > systems available. So I'm giving it predetermined extents and > skylines, > which are used for page breaking and page spacing purposes, only > after > which the RehearsalMark's stencil is computed. The drawback is that > it > could collide with something on top of it. > > However, there was a flaw in that code. When you have several scores > in > a bookpart, page-count and system-count override the total numbers > for > the whole bookpart, but I was counting them per score. Here is a > fixed > version: > > \version "2.22.2" > > \paper { > page-post-process = > #(lambda (paper pages) > (let ((n-systems 0) > (page-min #f) > (page-max #f)) > (for-each > (lambda (page) > (for-each > (lambda (line) > (let ((sys (ly:prob-property line 'system-grob))) > (if (ly:grob? sys) > (let ((sys-page (ly:grob-property sys 'page- > number))) > (set! n-systems (1+ n-systems)) > (set! page-min (if page-min > (min page-min sys-page) > sys-page)) > (set! page-max (if page-max > (max page-max sys-page) > sys-page)) > (ly:prob-property page 'lines))) > pages) > (ly:output-def-set-variable! paper 'n-systems n-systems) > (ly:output-def-set-variable! paper 'n-pages (1+ (- page-max > page-min) > } > > #(define-markup-command (page-info layout props arg) (markup?) > (ly:make-stencil > `(delay-stencil-evaluation > ,(delay > (let* ((n-systems (ly:output-def-lookup layout 'n-systems)) > (n-pages (ly:output-def-lookup layout 'n-pages))) > (ly:stencil-expr > (interpret-markup > layout > (cons `((n-systems . ,(number->string n-systems)) > (n-pages . ,(number->string n-pages))) > props) > arg) > '(0 . 0) > '(0 . 0))) > > \header { > subsubtitle = \markup \page-info \line { > Have \fromproperty #'n-systems systems > on \fromproperty #'n-pages pages > } > } >
Re: Displaying typesetting information at compile time
On Mon, 2022-03-21 at 17:28 +0100, Jean Abou Samra wrote: > > > Le 21/03/2022 à 17:24, Richard Shann a écrit : > > On Sun, 2022-03-20 at 20:09 +0100, Jean Abou Samra wrote: > > > > > [...] perhaps there is something altogether > > simpler? > > > > In that case, just output the info at the end of page-post-process > instead > of storing it and retrieving it later. > > \version "2.22.2" > > \paper { > page-post-process = > #(lambda (paper pages) > (let ((n-systems 0) > (page-min #f) > (page-max #f)) > (for-each > (lambda (page) > (for-each > (lambda (line) > (let ((sys (ly:prob-property line 'system-grob))) > (if (ly:grob? sys) > (let ((sys-page (ly:grob-property sys 'page- > number))) > (set! n-systems (1+ n-systems)) > (set! page-min (if page-min > (min page-min sys-page) > sys-page)) > (set! page-max (if page-max > (max page-max sys-page) > sys-page)) > (ly:prob-property page 'lines))) > pages) > (ly:message "~a systems on ~a pages" > n-systems > (1+ (- page-max page-min) > } > > \repeat unfold 10 { 1 1 \break } > \repeat unfold 13 { 1 1 \break } > Perfect! Thanks, I should have thought to track down documentation for page-post-process ... Richard
Re: Displaying typesetting information at compile time
Le 22/03/2022 à 09:15, Richard Shann a écrit : Perfect! Thanks, I should have thought to track down documentation for page-post-process ... Richard Ahem, well, like with a number of Scheme interfaces, that documentation is nonexistent. Jean