#(define song-list '()) #(define song-number 0) #(define (files-in-directory dirname) ;;; Generate list containing filenames (let ((dir (opendir dirname))) (let next ((f (readdir dir)) (files '())) (cond ((eof-object? f) (closedir dir) files) (else (next (readdir dir) (if (ly:regex-match? (ly:regex-exec (ly:make-regex "^(0|\\.)") f)) files (cons f files)))))))) #(define (file-to-stats filename) (set! song-list (cons filename song-list))) #(define additional-page-switch-label-list '()) #(define additional-page-numbers #f) normalPageNumbers = #(define-void-function (parser location) () (set! additional-page-numbers #f) ) additionalPageNumbers = #(define-void-function (parser location) () (set! additional-page-numbers #t) ) #(define (real-page-number layout label) (let ((table (ly:output-def-lookup layout 'label-page-table))) (if (list? table) (assoc-get label table) #f)) ) #(define display-pages-list '()) #(define (build-display-pages-list layout) (if (null? display-pages-list) (let calculate-display-page ((switch-label-list additional-page-switch-label-list)) (let* ((label (caar switch-label-list)) (is-additional (cdar switch-label-list)) (real-page (real-page-number layout label)) (rest-switch-label-list (cdr switch-label-list)) (display-page (if (null? rest-switch-label-list) (if is-additional (- real-page 1) real-page) (let* ((previous-label (caar rest-switch-label-list)) (previous-is-additional (cdar rest-switch-label-list)) (previous-display-page (calculate-display-page rest-switch-label-list))) (+ previous-display-page (if previous-is-additional (if is-additional 0 1) (if is-additional (- (- real-page (real-page-number layout previous-label)) 1) (- real-page (real-page-number layout previous-label))) ) ) ) )) ) (set! display-pages-list (acons label display-page display-pages-list)) display-page ))) display-pages-list ) % TODO: % Eigentlich können wir das direkt in oddFooderMarkup und evenFooterMarkup aufrufen % vermutlich sogar ohne den delay kram. Wir sollten außerdem einfach nur die property % page:page-number-string setzen dann klappts auch mit PDF Seiten #(define-markup-command (custom-page-number layout props label real-current-page-number) (symbol? number?) #:category other " @cindex referencing page number, in text Reference to a page number. @var{label} is the label set on the referenced page (using the @code{\\label} command), @var{gauge} a markup used to estimate the maximum width of the page number, and @var{default} the value to display when @var{label} is not found. (If the current book or bookpart is set to use roman numerals for page numbers, the reference will be formatted accordingly -- in which case the @var{gauge}'s width may require additional tweaking.)" (let* ((gauge-stencil (interpret-markup layout props "XXX")) (x-ext (ly:stencil-extent gauge-stencil X)) (y-ext (ly:stencil-extent gauge-stencil Y))) (ly:stencil-outline (ly:make-stencil `(delay-stencil-evaluation ,(delay (ly:stencil-expr (let* ((display-page (assq-ref (build-display-pages-list layout) label)) (real-current-page (if (negative? real-current-page-number) (real-page-number layout label) real-current-page-number)) (number-type (ly:output-def-lookup layout 'page-number-type)) (page-markup (if (assq-ref additional-page-switch-label-list label) (make-concat-markup (list (number-format number-type display-page) (make-char-markup (+ 97 (- real-current-page (real-page-number layout (let find-earliest-additional-label ((rest-additional-page-switch-label-list (member (cons label #t) additional-page-switch-label-list))) (if (cdadr rest-additional-page-switch-label-list) (find-earliest-additional-label (cdr rest-additional-page-switch-label-list)) (caar rest-additional-page-switch-label-list))) )))))) (number-format number-type (+ display-page (- real-current-page (real-page-number layout label)))) )) (page-stencil (interpret-markup layout props page-markup)) (gap (- (interval-length x-ext) (interval-length (ly:stencil-extent page-stencil X))))) (interpret-markup layout props (make-line-markup (list (make-hspace-markup gap) page-markup))))))) x-ext y-ext) (make-filled-box-stencil x-ext y-ext)))) includeSong = #(define-void-function (filename) (string?) #{ \bookOutputName #filename #} (ly:parser-parse-string (ly:parser-clone) (ly:format "\\include \"~a/~a/~a.ly\"" songPath filename filename)) (let ((label (gensym "index"))) (set! additional-page-switch-label-list (acons label additional-page-numbers additional-page-switch-label-list)) (set! song-list (acons (string->symbol filename) `( (label . ,label) (header . ,HEADER) (music . ,MUSIC) (layout . ,LAYOUT) (text-pages . ,(map (lambda (text) #{ \markuplist \setsongfilename $filename $text #}) TEXT_PAGES)) ) song-list)) )) blankpage = #(define-void-function () () (set! song-list (acons 'emptyPage '() song-list))) imagepage = #(define-void-function (xsize filename) (number? string?) (set! song-list (acons 'imagePage `((xsize . ,xsize) (filename . ,filename)) song-list))) markuppage = #(define-void-function (mkup) (markup?) (set! song-list (acons 'markupPage `((markup . ,mkup)) song-list))) #(define chapters '()) songsChapter = #(define-void-function (title) (string?) (set! chapters (cons (cons title (length song-list)) chapters))) #(define-markup-command (pagecenter layout props stuff)(markup?) (interpret-markup layout props (let ((halfpaperheight (/ (ly:output-def-lookup layout 'paper-height) 2)) (halfstuffheight (/ (interval-length (ly:stencil-extent (interpret-markup layout props stuff) Y)) 2))) (make-fill-line-markup (list (make-pad-to-box-markup '(0 . 0) (cons (- (- halfpaperheight halfstuffheight)) (+ halfpaperheight halfstuffheight)) stuff))) ))) songs = #(define-void-function () () (let* ((ordered (reverse song-list)) (total (length ordered)) ;; Ein Lied erzeugt nur dann einen PDF-Outline-Eintrag (/OUT), wenn ;; title oder starttext gesetzt sind (siehe build-full-title). Nur solche ;; Lieder duerfen als Kapitel-Kinder gezaehlt werden -- sonst wird die ;; /Count zu hoch und der erste Folgeeintrag (z.B. ein spaeteres Kapitel) ;; rutscht faelschlich als Kind mit hinein. (emits-bookmark? (lambda (e) (and (not (eq? (car e) 'emptyPage)) (not (eq? (car e) 'imagePage)) (not (eq? (car e) 'markupPage)) (let ((vars (extract-and-check-vars-from-header (assq-ref (cdr e) 'header) '(title starttext)))) (if (or (assq-ref vars 'title) (assq-ref vars 'starttext)) #t #f))))) (count-bookmark-songs (lambda (start end) (let loop ((i 0) (l ordered) (c 0)) (cond ((or (null? l) (>= i end)) c) ((< i start) (loop (+ i 1) (cdr l) c)) (else (loop (+ i 1) (cdr l) (if (emits-bookmark? (car l)) (+ c 1) c))))))) ;; chapters: (title . start-index). start-index = Anzahl der song-list- ;; Eintraege beim Aufruf von songsChapter = Index in `ordered`, ab dem ;; das Kapitel beginnt. (chapters-asc (sort chapters (lambda (a b) (< (cdr a) (cdr b))))) ;; pending: aufsteigende Liste von (start title count); count = Anzahl ;; der Lesezeichen-Lieder von diesem Kapitel bis zum Beginn des naechsten. (pending (let loop ((chs chapters-asc) (acc '())) (if (null? chs) (reverse acc) (let* ((title (caar chs)) (start (cdar chs)) (end (if (null? (cdr chs)) total (cdadr chs))) (cnt (count-bookmark-songs start end))) (loop (cdr chs) (cons (list start title cnt) acc)))))) ;; Stellt einer beliebigen Seite (markup-/image-/emptyPage) den Kapitel- ;; Eintrag (chapter-to-pdf-toc) bei, falls an Position `this-index` ein ;; Kapitel faellig ist, und entfernt es aus `pending`. So fuehrt die ;; Kapitel-Referenz zur ersten Seite nach dem \songsChapter -- egal ;; welcher Seitentyp das ist. Der Eintrag wird als unsichtbares Overlay ;; (\combine) beigelegt, damit er das Seitenlayout nicht veraendert; ;; \with-dimensions gibt dem sonst extent-losen pdfmark einen minimalen ;; Extent, damit er auch auf leeren Seiten nicht verworfen wird. (chapter-prefixed-markup (lambda (this-index base-markup) (if (and (pair? pending) (<= (car (car pending)) this-index)) (let ((cnt (caddr (car pending))) (title (cadr (car pending)))) (set! pending (cdr pending)) (make-combine-markup base-markup (make-with-dimensions-markup '(0 . 0) '(0 . 0.1) (make-chapter-to-pdf-toc-markup cnt title)))) base-markup))) (index 0)) (for-each (lambda (songitems) (let ((this-index index)) (set! index (+ index 1)) (ly:book-add-bookpart! (ly:parser-lookup '$current-book) (let ((filename (car songitems)) (songvars (cdr songitems))) (if (eq? filename 'emptyPage) #{ \bookpart { \markup { $(chapter-prefixed-markup this-index (make-null-markup)) } } #} (if (eq? filename 'markupPage) ;; Kapitelanfang auf einer markuppage: Kapitel-Eintrag wird dieser ;; Seite beigelegt (siehe chapter-prefixed-markup). #{ \bookpart { \markup { $(chapter-prefixed-markup this-index (assq-ref songvars 'markup)) } } #} (if (eq? filename 'imagePage) (let* ((xsize (assq-ref songvars 'xsize)) (filename (ly:format "~a/~a" imagePagePath (assq-ref songvars 'filename))) (img-markup #{ \markup { \pagecenter { \epsfile #X #xsize #filename } } #})) #{ \bookpart { \paper { %{ inner-margin = 0 outer-margin = 0 binding-offset = 0 top-margin = 0 bottom-margin = 0 %} print-page-number = ##f last-bottom-spacing = #'((basic-distance . 0) (minimum-distance . 0) (padding . 0)) page-count = 1 } \markup { $(chapter-prefixed-markup this-index img-markup) } } #} ) ;; Ist ein Kapitel faellig (Start <= aktuelle Position) und dies ein ;; echtes Lied, wird die Kapitelinfo an dieses Lied gehaengt und aus ;; `pending` entfernt. (let* ((newnumber (+ 1 song-number)) (chaptertitle (if (and (pair? pending) (<= (car (car pending)) this-index)) (cadr (car pending)) #f)) (chaptercount (if chaptertitle (caddr (car pending)) 0)) (header #{ \bookpart { $(assq-ref songvars 'header) \header { songfilename = $(symbol->string filename) myindexlabel = #(assq-ref songvars 'label) songnumber = #(number->string newnumber) chaptertitle = #chaptertitle chaptercount = #chaptercount } } #}) (music (assq-ref songvars 'music)) (layout (assq-ref songvars 'layout)) (text-pages (assq-ref songvars 'text-pages)) (label (assq-ref songvars 'label))) (if chaptertitle (set! pending (cdr pending))) (set! song-number newnumber) #{ \bookpart { $header \headerToTOC #header #label \score { $music \layout { $layout songfilename = $(symbol->string filename) } } $(add-text-pages text-pages) } #})))))))) ordered ))) #(define (boernel-stats) (let ( (songs (map (lambda (song) (symbol->string (car song))) (alist-delete 'emptyPage song-list))) (opticalline "---------------------------------------------------------")) (ly:warning (string-join (list opticalline (string-concatenate (list "Inkludiert: " (number->string (length songs)) " Lieder\n")) ;(string-join songs "\n") "Nicht inkludiert:" opticalline (string-join (sort-list (lset-difference string=? (files-in-directory songPath) songs) stringnumber (ly:regex-match-substring match x))) (cdr (iota 5))) #f))) #(define eps-references '()) #(define-public (eps-file-ref->stencil axis size just-embed file-name) (let* ((already-embedded (assq (string->symbol file-name) eps-references)) (counter (if already-embedded (cadr already-embedded) (if (null-list? eps-references) 1 (+ 1 (cadar eps-references))))) (form-name (ly:format "IDForm~a" counter)) (data-name (ly:format "ImageData~a" counter)) (eps-content (ly:gulp-file file-name)) (contents (ly:format "~a execform" form-name)) (bbox (if already-embedded (cddr already-embedded) (get-postscript-bbox (car (string-split eps-content #\nul))))) (bbox-size (if (= axis X) (- (list-ref bbox 2) (list-ref bbox 0)) (- (list-ref bbox 3) (list-ref bbox 1)) )) (factor (if (< 0 bbox-size) (exact->inexact (/ size bbox-size)) 0)) (scaled-bbox (map (lambda (x) (* factor x)) bbox)) ;; We need to shift the whole eps to (0,0), otherwise it will appear ;; displaced in lilypond (displacement will depend on the scaling!) (translate-string (ly:format "~a ~a translate" (- (list-ref bbox 0)) (- (list-ref bbox 1)))) (clip-rect-string (ly:format "~a ~a ~a ~a rectclip" (list-ref bbox 0) (list-ref bbox 1) (- (list-ref bbox 2) (list-ref bbox 0)) (- (list-ref bbox 3) (list-ref bbox 1))))) (if (not already-embedded) (set! eps-references (acons (string->symbol file-name) (cons counter bbox) eps-references))) (if bbox (ly:make-stencil (list 'embedded-ps (string-append (if (and already-embedded (not just-embed)) "" (ly:format " /~a currentfile << /Filter /SubFileDecode /DecodeParms << /EODCount 0 /EODString (*EOD*) >> >> /ReusableStreamDecode filter ~a *EOD* def /~a << /FormType 1 /BBox [~a ~a ~a ~a] /Matrix [ 1 0 0 1 0 0] /PaintProc { pop /ostate save def /showpage {} def /setpagedevice /pop load def ~a 0 setfileposition ~a cvx exec ostate restore } bind >> def " data-name eps-content form-name (list-ref bbox 0) (list-ref bbox 1) (list-ref bbox 2) (list-ref bbox 3) data-name data-name)) (if just-embed "" (ly:format " gsave currentpoint translate BeginEPSF ~a dup scale ~a ~a %%BeginDocument: ~a ~a %%EndDocument EndEPSF grestore " factor translate-string clip-rect-string file-name contents )))) ;; Stencil starts at (0,0), since we have shifted the eps, and its ;; size is exactly the size of the scaled bounding box (if just-embed '(0 . 0) (cons 0 (- (list-ref scaled-bbox 2) (list-ref scaled-bbox 0)))) (if just-embed '(0 . 0) (cons 0 (- (list-ref scaled-bbox 3) (list-ref scaled-bbox 1))))) (ly:make-stencil "" '(0 . 0) '(0 . 0))) )) #(define-markup-command (epsfileref layout props axis size file-name) (number? number? string?) #:category graphic " @cindex inlining an Encapsulated PostScript image Inline an EPS image. The image is scaled along @var{axis} to @var{size}. @lilypond[verbatim,quote] \\markup { \\general-align #Y #DOWN { \\epsfile #X #20 #\"context-example.eps\" \\epsfile #Y #20 #\"context-example.eps\" } } @end lilypond" (if (ly:get-option 'safe) (interpret-markup layout props "not allowed in safe") (eps-file-ref->stencil axis size #f file-name) )) #(define-markup-command (epsfileembed layout props file-name) (string?) #:category graphic " @cindex inlining an Encapsulated PostScript image Inline an EPS image. The image is scaled along @var{axis} to @var{size}. @lilypond[verbatim,quote] \\markup { \\general-align #Y #DOWN { \\epsfile #X #20 #\"context-example.eps\" \\epsfile #Y #20 #\"context-example.eps\" } } @end lilypond" (if (ly:get-option 'safe) (interpret-markup layout props "not allowed in safe") (eps-file-ref->stencil X 30 #t file-name) ))