372 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			372 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| #(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
 | |
| )
 | |
| 
 | |
| 
 | |
| #(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))
 | |
|                         (page-markup
 | |
|                           (if (assq-ref additional-page-switch-label-list label)
 | |
|                               (make-concat-markup (list (number-format 'arabic 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 'arabic (+ 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 (parser location 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)
 | |
|           (acons 'label label
 | |
|             (acons 'header HEADER
 | |
|               (acons 'music MUSIC
 | |
|                 (acons 'layout LAYOUT
 | |
|                   (acons 'text-pages
 | |
|                     (map (lambda (text)
 | |
|                       #{ \markuplist \setsongfilename $filename $text #})
 | |
|                       TEXT_PAGES)
 | |
|                     '())))))
 | |
|           song-list))
 | |
|     ))
 | |
| 
 | |
| blankpage =
 | |
| #(define-void-function (parser location) ()
 | |
|     (set! song-list
 | |
|       (acons 'emptyPage
 | |
|         '()
 | |
|         song-list)))
 | |
| 
 | |
| imagepage =
 | |
| #(define-void-function (parser location xsize filename) (number? string?)
 | |
|     (set! song-list
 | |
|       (acons 'imagePage
 | |
|         (acons 'xsize xsize (acons 'filename filename '()))
 | |
|         song-list)))
 | |
| 
 | |
| #(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 (parser location) ()
 | |
|  (for-each (lambda (songitems)
 | |
|    (ly:book-add-bookpart! (ly:parser-lookup '$current-book)
 | |
|     (let ((filename (car songitems))
 | |
|           (songvars (cdr songitems)))
 | |
|       (if (eq? filename 'emptyPage)
 | |
|           #{ \bookpart { \markup { \null } } #}
 | |
|       (if (eq? filename 'imagePage)
 | |
|           (let ((xsize (assq-ref songvars 'xsize))
 | |
|                 (filename (ly:format "~a/~a" imagePagePath (assq-ref songvars '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 { \pagecenter { \epsfile #X #xsize #filename } }
 | |
|           } #}
 | |
|           )
 | |
|           (let* ((newnumber (+ 1 song-number))
 | |
|                  (header #{ \bookpart { $(assq-ref songvars 'header) \header {
 | |
|                    songfilename = $(symbol->string filename)
 | |
|                    myindexlabel = #(assq-ref songvars 'label)
 | |
|                    songnumber = #(number->string newnumber)
 | |
|                  } } #})
 | |
|                  (music (assq-ref songvars 'music))
 | |
|                  (layout (assq-ref songvars 'layout))
 | |
|                  (text-pages (assq-ref songvars 'text-pages))
 | |
|                  (label (assq-ref songvars 'label)))
 | |
|             (set! song-number newnumber)
 | |
|             #{
 | |
|               \bookpart {
 | |
|                 $header
 | |
|                 \headerToTOC #header #label
 | |
|                 \score { $music \layout { $layout } }
 | |
|                 $(add-text-pages text-pages)
 | |
|               }
 | |
|             #}))))))
 | |
|    (reverse song-list)
 | |
|    ))
 | |
| 
 | |
| #(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) string<?) "\n")
 | |
|      opticalline
 | |
|      ) "\n" )
 | |
| )))
 | |
| 
 | |
| %%%%%%%%%%%%%%%%%%%%%%%%%%%
 | |
| %% Include Images once and reference them:
 | |
| #(define bbox-regexp
 | |
|   (ly:make-regex "%%BoundingBox:[ \t]+([0-9-]+)[ \t]+([0-9-]+)[ \t]+([0-9-]+)[ \t]+([0-9-]+)"))
 | |
| 
 | |
| #(define (get-postscript-bbox string)
 | |
|   "Extract the bbox from STRING, or return #f if not present."
 | |
|   (let*
 | |
|       ((match (ly:regex-exec bbox-regexp string)))
 | |
| 
 | |
|     (if match
 | |
|         (map (lambda (x)
 | |
|                (string->number (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)
 | |
|       ))
 |