Author SHA1 Message Date
tux 39d9e8c0d5 use lilypond 2.27 and be compatibel to 2.26 2026-10-22 12:54:22 +02:00
tux dfd72cd64d layout size for inline-scores 2026-10-22 11:59:27 +02:00
tux d0db6fae69 finetuning chord lyrics engraver 2026-10-22 11:47:48 +02:00
tux 2359a7c5ae Mehrere Lieder auf eine Seite 2026-10-11 23:20:40 +02:00
zuk 809100b2f3 define rehearsalMarkFormatter 2026-08-28 13:11:47 +02:00
tux 7de31cf0dd chapter toc 2026-07-07 12:16:13 +02:00
tux ae72640b1a chapters for every pagetype 2026-07-07 11:05:47 +02:00
tux 7076b16b63 Use chapters for digital toc
* introduce \songsChapter and \markuppage
* have nested chapters in PDF toc
2026-07-05 14:09:44 +02:00
tux 50e08220c4 make customEps path resolution more robust 2026-07-01 17:58:10 +02:00
tux 40f483bc67 default to numeric time signatures 2026-06-21 16:44:49 +02:00
tux 9b1297f675 fix tag group usage in markups 2026-06-04 00:05:42 +02:00
zuk aed11a70a7 Add meloref to author system 2026-05-12 10:42:14 +02:00
zuk 92a129f346 Fix double melody year in songinfo 2026-05-03 22:22:59 +02:00
zuk bb940b2a3b Fix transposeGlobal: Make additional transpositions possible 2026-04-22 11:45:57 +02:00
tux 997f757cd6 Chordpro export 2026-04-18 16:47:22 +02:00
tux 6e528a5328 fix markup tag group trouble accross songs 2026-04-10 14:29:20 +02:00
zuk 71c8c0385c switch swingStyle to textMark 2026-03-31 18:55:12 +02:00
tux f075946777 use right translationAuthorPrefix in authorContributionFormat 2026-03-12 22:25:50 +01:00
tux a0de02126c no "add" as additionalPitchPrefix 2026-03-10 19:17:40 +01:00
tux 7ece3b9c10 underline for LyricText 2026-03-09 17:01:21 +01:00
tux 7fc99e8883 use new chords and page references of LilyPond 2.25.35 2026-03-08 13:37:31 +01:00
tux b3feb3aa6d padding for stop tags and refactoring 2026-02-22 20:33:18 +01:00
tux 7b166f6fc3 pad left for stanzas to have a minimum distance to SystemStartBar 2026-02-22 13:22:45 +01:00
tux 9c437d0f06 reset tag groups for each song 2026-02-10 17:18:52 +01:00
tux a52f993678 more flexible titeling 2026-02-01 01:45:10 +01:00
tux bbd6d44455 Autorensystem flexibilisiert 2026-01-11 20:03:31 +01:00
zuk f68e2f10ae implement default bridge style 2025-12-29 18:06:00 +01:00
tux 463d61fbd9 fix customize layout sizing 2025-12-22 11:29:32 +01:00
tux 2d14a5b632 new engraver for spacing in chordlyrics 2025-12-15 21:41:45 +01:00
tux 368a1b96aa rework stanza handler 2025-12-15 11:49:30 +01:00
tux f57b1c4ec3 customize text chord distance in old system, too 2025-12-15 01:47:05 +01:00
tux e530bdf090 make verselayout really work 2025-12-15 01:26:19 +01:00
zuk c97c856b05 Use \tempo command for midi speed
* Remove Metronome mark engraver
* Remove midiQuarterNoteSpeed
2025-12-13 12:50:01 +01:00
tux 76b81a9968 no breaks in toc after section title 2025-11-24 20:45:00 +01:00
tux 3ff5a36106 better load song include data in windows 2025-11-24 16:47:13 +01:00
20 changed files with 2065 additions and 375 deletions

No files matched your search

+1 -1
View File
@@ -1,8 +1,8 @@
# ---> Lilypond # ---> Lilypond
*.pdf *.pdf
*.cho
*.ps *.ps
*.midi *.midi
*.mid *.mid
*.log *.log
*~ *~
+18 -2
View File
@@ -21,15 +21,28 @@
))))) )))))
(scm-load "resolve_inherits.scm") (scm-load "resolve_inherits.scm")
(scm-load "yaml_parser.scm"))) (scm-load "yaml_parser.scm")))
#(define AUTHOR_DATA (if (defined? 'AUTHOR_DATA) AUTHOR_DATA (parse-yml-file "../../lilypond-song-includes/data/authors.yml")))
#(define SONG_DATA (if (defined? 'SONG_DATA) SONG_DATA (parse-yml-file "../../lilypond-song-includes/data/songs.yml")))
#(define (song-includes-data-path filename)
(string-join
(list
(dirname (dirname (dirname (dirname (current-filename)))))
"lilypond-song-includes"
"data"
filename)
file-name-separator-string))
#(define AUTHOR_DATA (if (defined? 'AUTHOR_DATA) AUTHOR_DATA (parse-yml-file (song-includes-data-path "authors.yml"))))
#(define SONG_DATA (if (defined? 'SONG_DATA) SONG_DATA (parse-yml-file (song-includes-data-path "songs.yml"))))
\include #(if (ly:version? < '(2 27 0)) "compat_lilypond_2_26.ily" "../void.ily")
\include "merge_rests_engraver_override.ily" \include "merge_rests_engraver_override.ily"
\include "basic_format_and_style_settings.ily" \include "basic_format_and_style_settings.ily"
\include "eps_file_from_song_dir.ily" \include "eps_file_from_song_dir.ily"
\include "embedded_songs.ily"
\include "title_with_category_images.ily" \include "title_with_category_images.ily"
\include "chord_settings.ily" \include "chord_settings.ily"
\include "chordpro.ily"
\include "transposition.ily" \include "transposition.ily"
\include "markup_tag_groups_hack.ily"
\include "verses_with_chords.ily" \include "verses_with_chords.ily"
\include "arrows_in_scores.ily" \include "arrows_in_scores.ily"
\include "swing_style.ily" \include "swing_style.ily"
@@ -43,7 +56,10 @@ HEADER = {}
MUSIC = {} MUSIC = {}
TEXT = \markuplist {} TEXT = \markuplist {}
TEXT_PAGES = #f TEXT_PAGES = #f
EMBEDDED_SONGS = #'()
verseChords = {} verseChords = {}
firstVoice = {} firstVoice = {}
global = {} global = {}
\resetTagGroups
@@ -29,6 +29,11 @@
(if (null? stanzanumbers) (if (null? stanzanumbers)
refString refString
(ly:format refStringWithNumbers (string-join (map (lambda (stanzanumber) (ly:format "~a" stanzanumber)) stanzanumbers) ", "))))) (ly:format refStringWithNumbers (string-join (map (lambda (stanzanumber) (ly:format "~a" stanzanumber)) stanzanumbers) ", ")))))
bridgeMarkupFormatter = #(lambda (layout props stanzanumbers)
(interpret-markup layout props
(if (null? stanzanumbers)
bridgeString
(ly:format bridgeStringWithNumbers (string-join (map (lambda (stanzanumber) (ly:format "~a" stanzanumber)) stanzanumbers) ", ")))))
} }
generalLayout = \layout { generalLayout = \layout {
@@ -49,8 +54,11 @@ generalLayout = \layout {
\context { \context {
\Score \Score
\remove "Bar_number_engraver" \remove "Bar_number_engraver"
\remove "Metronome_mark_engraver"
\RemoveEmptyStaves \RemoveEmptyStaves
\override VerticalAxisGroup.remove-first = ##t \override VerticalAxisGroup.remove-first = ##t
\numericTimeSignature
rehearsalMarkFormatter = #format-mark-box-alphabet
\overrideTimeSignatureSettings \overrideTimeSignatureSettings
4/4 % timeSignatureFraction 4/4 % timeSignatureFraction
1/4 % baseMomentFraction 1/4 % baseMomentFraction
@@ -78,6 +86,27 @@ generalLayout = \layout {
} }
} }
#(define (customized-layout base-layout)
(let
((custom-size (ly:output-def-lookup base-layout 'size #f)))
(if custom-size (layout-set-staff-size custom-size))))
% Scores in Markups (z.B. inline-score) kopieren ihr \layout schon beim Parsen,
% also bevor customized-layout greift. Deshalb nachträglich anpassen.
#(define (customize-embedded-score-layouts! obj)
(cond
((ly:score? obj)
(for-each
(lambda (def)
(let ((custom-size (ly:output-def-lookup def 'size #f))
(scope (ly:output-def-scope def)))
(if custom-size
(layout-set-absolute-staff-size-in-module scope (* custom-size (eval 'pt scope))))))
(ly:score-output-defs obj)))
((pair? obj)
(customize-embedded-score-layouts! (car obj))
(customize-embedded-score-layouts! (cdr obj)))))
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% kleine Helferlein: %%% kleine Helferlein:
@@ -126,74 +155,129 @@ romanStanza =
#(define-music-function (parser location) () #(define-music-function (parser location) ()
#{ \override StanzaNumber.style = #'roman #}) #{ \override StanzaNumber.style = #'roman #})
#(define (number-or-number-list? x) (or (number? x) (number-list? x)))
% "1,4" -> (1 4); Einträge, die keine Zahl sind, bleiben Strings ("1b,2b" -> ("1b" "2b"))
#(define (stanza-numbers-from-string str)
(map (lambda (s) (or (string->number s) s))
(remove string-null? (map string-trim-both (string-split str #\,)))))
% Kein number? hier, sonst kann der Parser 1,4 nicht mehr als Liste lesen
#(define (stanza-numbers? x) (or (number-list? x) (string? x)))
override-stanza = override-stanza =
#(define-music-function (parser location stanzanumbers) (number-list?) #(define-music-function (stanzanumbers) (number-or-number-list?)
#{ #{
\once \override StanzaNumber.details.custom-stanzanumber-override = #stanzanumbers \once \override StanzaNumber.details.custom-stanzanumber-override = #(if (number? stanzanumbers) (list stanzanumbers) stanzanumbers)
#} #}
) )
#(define (stanza . stanzanumbers) #(define (romanize-stanza-numbers numbers style)
(if (eq? style 'roman)
(map (lambda (n) (if (number? n) (format #f "~@r" n) n)) numbers)
numbers))
#(define (format-stanza-numbers numbers style)
(string-join
(map (lambda (n) (format #f stanzaFormat n)) (romanize-stanza-numbers numbers style))
", "))
% Strophennummer, die erst beim Setzen aus den Eigenschaften des StanzaNumber-Grobs gebaut wird
% (details.custom-stanza-type, details.custom-stanza-numbers, style, details.custom-inline-text).
% So können \fstanza, \ref, \bridge und \repStartWithTag im selben Zeitschritt kombiniert werden.
#(define-markup-command (formatted-stanza layout props) ()
#:properties ((details '()) (style #f))
(let* ((realstanza (ly:assoc-get 'custom-realstanza details #f))
(type (ly:assoc-get 'custom-stanza-type details 'verse))
(numbers (ly:assoc-get 'custom-stanzanumber-override details
(ly:assoc-get 'custom-stanza-numbers details '())))
(inline-text (ly:assoc-get 'custom-inline-text details #f))
(inline-direction (ly:assoc-get 'custom-inline-direction details CENTER))
(rep-start (and inline-text (eqv? inline-direction LEFT)))
(roman-numbers (romanize-stanza-numbers numbers style))
(stanza-stencil
(and realstanza
(case type
((ref) ((ly:output-def-lookup layout 'refMarkupFormatter) layout props roman-numbers))
((bridge) ((ly:output-def-lookup layout 'bridgeMarkupFormatter) layout props roman-numbers))
(else (interpret-markup layout props (format-stanza-numbers numbers style))))))
(padded-stanza-stencil
(and stanza-stencil
(interpret-markup layout props (make-pad-left-markup 1 (make-stencil-markup stanza-stencil))))))
(if rep-start
(interpret-markup layout props
(make-concat-markup
(append
(if padded-stanza-stencil (list (make-stencil-markup padded-stanza-stencil) (make-hspace-markup 1)) '())
(list (make-override-markup '(font-series . normal) inline-text)))))
(or padded-stanza-stencil empty-stencil))))
#(define (formatted-stanza-music type stanzanumbers)
#{ #{
\once \override StanzaNumber.details.custom-realstanza = ##t % set this to signal that there is a real stanza and no repeat signs \once \override StanzaNumber.details.custom-realstanza = ##t % set this to signal that there is a real stanza and no repeat signs
\applyContext \once \override StanzaNumber.details.custom-stanza-type = #type
#(lambda (context) \once \override StanzaNumber.details.custom-stanza-numbers = #stanzanumbers
(let* ((stanzanumbers-override (ly:assoc-get 'custom-stanzanumber-override (ly:assoc-get 'details (ly:context-grob-definition context 'StanzaNumber) '()) #f)) \stanza \markup \formatted-stanza
(stanza-style (ly:assoc-get 'style (ly:context-grob-definition context 'StanzaNumber))) #})
(stanza-format (lambda (stanzanumber) (format #f (if (eq? stanza-style 'roman) romanStanzaFormat stanzaFormat) stanzanumber))))
(ly:context-set-property! context 'stanza % \fstanza 1 -> "1."
(string-join (map stanza-format % \fstanza 1,4 -> "1., 4." (nur im Notenmodus, z.B. \chordverse { \fstanza 1,4 } ...)
(if stanzanumbers-override stanzanumbers-override stanzanumbers)) % \fstanza "1,4" -> "1., 4." (auch im \lyricmode, dort versteht LilyPond 1,4 nicht als Liste)
", ")))) fstanza =
#} #(define-music-function (stanzanumbers) (stanza-numbers?)
) (formatted-stanza-music 'verse
(if (string? stanzanumbers) (stanza-numbers-from-string stanzanumbers) stanzanumbers)))
ref = ref =
#(define-music-function (stanzanumbers lyrics) ((number-list? (list)) ly:music?) #(define-music-function (stanzanumbers lyrics) ((number-list? (list)) ly:music?)
#{ \lyricmode { #{ \lyricmode {
\once \override StanzaNumber.details.custom-realstanza = ##t % set this to signal that there is a real stanza and no repeat signs #(formatted-stanza-music 'ref stanzanumbers)
\set stanza = #(make-on-the-fly-markup (lambda (layout props m) ((ly:output-def-lookup layout 'refMarkupFormatter) layout props stanzanumbers)) (make-null-markup)) #lyrics
}
#}
)
bridge =
#(define-music-function (stanzanumbers lyrics) ((number-list? (list)) ly:music?)
#{ \lyricmode {
#(formatted-stanza-music 'bridge stanzanumbers)
#lyrics #lyrics
} }
#} #}
) )
% prints a repStart Sign as stanza if the tag 'repeats is kept. % prints a repStart Sign as stanza if the tag 'repeats is kept.
% if there was a stanza already set by the stanza function with StanzaNumber.details.custom-realstanza = ##t we set that also as stanza. % if there is a stanza set by \fstanza in the same moment, \formatted-stanza prints both.
repStartWithTag = \lyricmode { % Sets custom-inline-text for ChordPro export so it can collect the repeat sign separately
repStartWithTag =
#(define-music-function () ()
#{ \lyricmode {
\tag #'repeats { \tag #'repeats {
\applyContext \once \override StanzaNumber.details.custom-inline-text = \repStart
#(lambda (context) \once \override StanzaNumber.details.custom-inline-direction = #LEFT
(let ((lastStanza (ly:context-property context 'stanza)) \stanza \markup \formatted-stanza
(printLastStanza (ly:assoc-get 'custom-realstanza (ly:assoc-get 'details (ly:context-grob-definition context 'StanzaNumber) '()) #f))
(stanzaFontSeries (ly:assoc-get 'font-series (ly:context-grob-definition context 'StanzaNumber) 'normal)))
(ly:context-set-property! context 'stanza
(make-concat-markup
(if printLastStanza
(list (make-override-markup `(font-series . ,stanzaFontSeries) lastStanza) (make-hspace-markup 1) repStart)
(list repStart)
)))))
\once \override StanzaNumber.font-series = #'normal
} }
} } #})
repStopWithTag = \lyricmode { repStopWithTag = \lyricmode {
\tag #'repeats { \tag #'repeats {
\once \override StanzaNumber.details.custom-inline-text = \repStop
\once \override StanzaNumber.details.custom-inline-direction = #RIGHT
\once \override StanzaNumber.font-series = #'normal \once \override StanzaNumber.font-series = #'normal
\once \override StanzaNumber.direction = 1 \once \override StanzaNumber.direction = 1
\set stanza = \markup { \repStop } \stanza \markup { \pad-x-right #1 \repStop }
} }
} }
rightHyphen = \lyricmode { rightHyphen = \lyricmode {
\once \override StanzaNumber.font-series = #'normal \once \override StanzaNumber.font-series = #'normal
\once \override StanzaNumber.direction = 1 \once \override StanzaNumber.direction = 1
\set stanza = "-" \stanza "-"
} }
leftHyphen = \lyricmode { leftHyphen = \lyricmode {
\once \override StanzaNumber.font-series = #'normal \once \override StanzaNumber.font-series = #'normal
\set stanza = "-" \stanza "-"
} }
multiVerseSkips = multiVerseSkips =
@@ -259,9 +343,23 @@ rufWithMarkup =
\lyricmode { \lyricmode {
\once \override StanzaNumber.font-series = #'normal \once \override StanzaNumber.font-series = #'normal
\once \override StanzaNumber.direction = 1 \once \override StanzaNumber.direction = 1
\set stanza = #text \stanza #text
} }
#}) #})
ruf = ruf =
#(define-music-function (text) (string?) #(define-music-function (text) (string?)
(rufWithMarkup (make-ruf-style-markup text))) (rufWithMarkup (make-ruf-style-markup text)))
underlineOn =
#(define-music-function () ()
#{
\override LyricText.stencil =
#(lambda (grob)
(grob-interpret-markup grob (make-underline-markup (ly:grob-property grob 'text))))
#})
underlineOff =
#(define-music-function () ()
#{
\revert LyricText.stencil
#})
+14 -62
View File
@@ -40,34 +40,19 @@ shiftChords = #(define-music-function (parser location xshift chords) (number? l
altChord = altChord =
#(define-music-function (parser location mainchord altchord) (ly:music? ly:music?) #(define-music-function (parser location mainchord altchord) (ly:music? ly:music?)
(let* ((remove-point-and-click (let* ((chord-name (lambda (in-pitches bass inversion context)
(lambda (grob) (make-line-markup (list
(ly:grob-set-property! grob 'cause #f) (ignatzek-chord-names in-pitches bass inversion context)
(ly:text-interface::print grob))) (make-hspace-markup 0.3)
(chord-name (lambda (in-pitches bass inversion context) #{ (parenthesis-ignatzek-chord-names (music-pitches (transposable (cons (car (music-pitches mainchord)) (car in-pitches)) (music-clone altchord))) '() '() context)
\markup { ))
\translate #'(-0.5 . 0) )))
\score {
\chords { \transposable #(cons (car (music-pitches mainchord)) (car in-pitches)) { #(music-clone mainchord) \klamm #(music-clone altchord) } }
\layout {
\LAYOUT
\context {
\ChordNames
\override ChordName.extra-spacing-width = #'(0 . 0.3)
\override ChordName.stencil = #remove-point-and-click
}
\context {
\Score
\override SpacingSpanner.spacing-increment = 0
}
}
}
}#})))
#{ #{
\once \set chordNameFunction = #chord-name \once \set chordNameFunction = #chord-name
#mainchord #mainchord
#})) #}))
% Akkorde werden so transponiert, dass sie passen, wenn man mit Kapo im angegebenen Bund spielt % Akkorde werden so transponiert, dass sie passen, wenn man mit Kapo im angegebenen Bund spielt
capoTranspose = capoTranspose =
#(define-music-function (fret chords) (number? ly:music?) #(define-music-function (fret chords) (number? ly:music?)
@@ -80,41 +65,8 @@ capoTranspose =
(ly:make-pitch 0 0) (ly:make-pitch 0 0)
chords)) chords))
% kleine Mollakkorde und Alteration ausgeschrieben
#(define (note-name->german-markup-nosym pitch lowercase?)
(define (pitch-alteration-semitones pitch) (inexact->exact (round (* (ly:pitch-alteration pitch) 2))))
(define (accidental->markup alteration name)
(if (= alteration 0)
(make-line-markup (list empty-markup))
(if (= alteration FLAT)
(if (equal? name "B")
""
; (make-line-markup (list (make-hspace-markup 0.2)
; (make-tiny-markup (make-raise-markup 1.2
; (make-musicglyph-markup (assoc-get alteration standard-alteration-glyph-name-alist ""))))
; ))
(if (or (equal? name "E") (equal? name "A")) "s" "es"))
"is")
))
(define (conditional-string-downcase str condition)
(if condition (string-downcase str) str))
(let* ((name (ly:pitch-notename pitch))
(alt-semitones (pitch-alteration-semitones pitch))
(n-a (if (member (cons name alt-semitones) `((6 . -1) (6 . -2)))
(cons 7 (+ 0 alt-semitones))
(cons name alt-semitones))))
(make-line-markup
(list
(make-simple-markup
(conditional-string-downcase
(vector-ref #("C" "D" "E" "F" "G" "A" "H" "B") (car n-a))
lowercase?))
(accidental->markup (/ (cdr n-a) 2) (vector-ref #("C" "D" "E" "F" "G" "A" "H" "B") (car n-a)) ))))
)
% additional bass notes should get uppercased % additional bass notes should get uppercased
#(define (bassnote-name->german-markup-nosym pitch lowercase?)(note-name->german-markup-nosym pitch #f)) #(define (bassnote-name->german-markup-nosym pitch lowercase?)((chord-name:name-markup 'deutsch) pitch #f))
defaultChordPrintings = { defaultChordPrintings = {
<c g>-\markup { \super "5" } <c g>-\markup { \super "5" }
@@ -157,15 +109,15 @@ generalLayout = \layout {
\generalLayout \generalLayout
\context { \context {
\ChordNames \ChordNames
\semiGermanChords
\override ChordName.font-size = \songScoreChordFontSize \override ChordName.font-size = \songScoreChordFontSize
\override ChordName.font-series = \songChordFontSeries \override ChordName.font-series = \songChordFontSeries
\override ChordName.font-family = #'serif \override ChordName.font-family = #'serif
chordNameLowercaseMinor = ##t chordNameLowercaseMinor = ##t
chordChanges = ##t chordChanges = ##t
% eigenen chordRootNamer damit F# = Fis und Gb = Ges (also alteration ausgeschrieben) chordRootNamer = #(chord-name:name-markup 'deutsch)
chordRootNamer = #note-name->german-markup-nosym
chordNoteNamer = #bassnote-name->german-markup-nosym chordNoteNamer = #bassnote-name->german-markup-nosym
additionalPitchPrefix = ""
majorSevenSymbol = "maj7" majorSevenSymbol = "maj7"
chordNameExceptions = \chordNameExceptions chordNameExceptions = \chordNameExceptions
} }
@@ -203,7 +155,7 @@ Ensure_first_chord_after_line_break_printed_engraver =
; the current chord handling implementation in lilypond uses 'begin-of-line-visible to mark repeated chords ; the current chord handling implementation in lilypond uses 'begin-of-line-visible to mark repeated chords
(ly:grob-set-property! grob 'begin-of-line-visible #f)) (ly:grob-set-property! grob 'begin-of-line-visible #f))
(set! last-system-column-rank current-system-column-rank) (set! last-system-column-rank current-system-column-rank)
(ly:chord-name::after-line-breaking grob) (item::enforce-musical-break-visibility grob)
))))))) )))))))
% If you add this engraver to ChordNames Context chords get only printed on chordchanges and not at newline. % If you add this engraver to ChordNames Context chords get only printed on chordchanges and not at newline.
@@ -214,4 +166,4 @@ Ignoring_newline_chord_changes_engraver =
((chord-name-interface this-engraver grob source-engraver) ((chord-name-interface this-engraver grob source-engraver)
(when (and (ly:context-property ctx 'chordChanges #f) (ly:grob-property grob 'begin-of-line-visible #f)) (when (and (ly:context-property ctx 'chordChanges #f) (ly:grob-property grob 'begin-of-line-visible #f))
(ly:grob-suicide! grob) (ly:grob-suicide! grob)
))))) )))))
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,11 @@
% Abwärtskompatibilität zu LilyPond 2.26.
% Wird von all.ily nur eingebunden, wenn die laufende LilyPond-Version älter als 2.27 ist.
% Alles andere ist für die aktuelle 2.27 geschrieben.
% Ab 2.27 gibt es \stanza als Musikfunktion (StanzaEvent), in 2.26 nur die Kontext-Property stanza.
stanza =
#(define-music-function (text) (markup?)
(context-spec-music (make-property-set 'stanza text) 'Bottom))
% Ab 2.27 heißt ly:chord-name::after-line-breaking item::enforce-musical-break-visibility.
#(define item::enforce-musical-break-visibility ly:chord-name::after-line-breaking)
@@ -2,16 +2,18 @@
poetPrefix = "Worte:" poetPrefix = "Worte:"
composerPrefix = "Weise:" composerPrefix = "Weise:"
compositionPrefix = "Satz:" compositionPrefix = "Satz:"
adaptionTextPrefix = "Bearbeitung Text:" adaptionTextPrefix = "Bearbeitung:"
adaptionMusicPrefix = "Bearbeitung Musik:" adaptionMusicPrefix = "Bearbeitung:"
poetAndComposerEqualPrefix = "Worte und Weise:" poetAndComposerEqualPrefix = "Worte und Weise:"
voicePrefix = "Stimme:" voicePrefix = "Stimme:"
versePrefix = "Strophe:" versePrefix = "Strophe:"
refPrefix = "Refrain:"
translationAuthorPrefix = "Übersetzung:" translationAuthorPrefix = "Übersetzung:"
translationPrefix = "Übersetzung:" translationPrefix = "Übersetzung:"
pronunciationPrefix = "Aussprache:" pronunciationPrefix = "Aussprache:"
interludePrefix = "Zwischenspiel:" interludePrefix = "Zwischenspiel:"
bridgePrefix = "Bridge:" bridgePrefix = "Bridge:"
author-joiner = #(lambda (author-list) (string-join author-list ", "))
authorFormat = authorFormat =
#(lambda (noDetails name trail_name birth_year death_year organization) #(lambda (noDetails name trail_name birth_year death_year organization)
@@ -31,6 +33,114 @@
"" ""
))) )))
authorContributionFormat =
#(lambda* (render-contribution-group render-partial-contribution-group #:key
(poetIds '())
(translatorIds '())
(versePoetData '())
(composerIds '())
(verseComposerData '())
(refComposerIds '())
(voiceComposerData '())
(compositionIds '())
(adaptionTextIds '())
(adaptionMusicIds '())
(bridgeIds '())
(interludeIds '())
(year_text #f)
(year_translation #f)
(year_melody #f)
(year_melody_meloref #f)
(year_composition #f)
(year_adaption_text #f)
(year_adaption_music #f)
(poetAndComposerEqualPrefix "")
(poetPrefix "")
(composerPrefix "")
(translationAuthorPrefix "")
(pronunciationPrefix "")
(compositionPrefix "")
(adaptionTextPrefix "")
(adaptionMusicPrefix "")
(bridgePrefix "")
(interludePrefix "")
(refPrefix ""))
(if (and
(equal? poetIds composerIds)
(null? translatorIds)
(null? versePoetData)
(null? verseComposerData)
(null? refComposerIds)
(null? voiceComposerData)
(null? compositionIds)
(null? adaptionTextIds)
(null? adaptionMusicIds)
(null? bridgeIds)
(null? interludeIds))
(list
(join-present (list
(render-contribution-group poetAndComposerEqualPrefix poetIds)
(if (equal? year_text year_melody) year_text (join-present (list year_text year_melody) "/"))
) ", ")
#f)
(list
(if (and (null? poetIds) (null? versePoetData) (null? translatorIds)) #f
(string-append
poetPrefix
" "
(join-present (list
(join-present (list
(render-contribution-group "" poetIds)
year_text
) ", ")
(render-partial-contribution-group 'versePrefix versePoetData)
(join-present (list
(render-contribution-group adaptionTextPrefix adaptionTextIds)
year_adaption_text
) ", ")
(join-present (list
(render-contribution-group translationAuthorPrefix translatorIds)
year_translation
) ", ")
) "; ")
))
(if (and
(null? composerIds)
(null? compositionIds)
(null? adaptionMusicIds)
(null? verseComposerData)
(null? refComposerIds)
(null? voiceComposerData)
(null? bridgeIds)
(null? interludeIds)) #f
(string-append
composerPrefix
" "
(join-present (list
(join-present (list
(render-contribution-group "" composerIds)
year_melody
) ", ")
(render-partial-contribution-group 'versePrefix verseComposerData)
(join-present (list
(render-contribution-group refPrefix refComposerIds)
year_melody_meloref
) ", ")
(render-partial-contribution-group 'voicePrefix voiceComposerData)
(join-present (list
(render-contribution-group compositionPrefix compositionIds)
year_composition
) ", ")
(join-present (list
(render-contribution-group adaptionMusicPrefix adaptionMusicIds)
year_adaption_music
) ", ")
(render-contribution-group bridgePrefix bridgeIds)
(render-contribution-group interludePrefix interludeIds)
) "; ")
)))))
songinfoMarkup = songinfoMarkup =
#(make-on-the-fly-markup #(make-on-the-fly-markup
(lambda (layout props m) (lambda (layout props m)
@@ -45,13 +155,15 @@
(year_melody (chain-assoc-get 'songinfo:year_melody props #f)) (year_melody (chain-assoc-get 'songinfo:year_melody props #f))
(poet-with-year (if (and poet-maybe-with-composer year_text) (string-append poet-maybe-with-composer ", " year_text) poet-maybe-with-composer)) (poet-with-year (if (and poet-maybe-with-composer year_text) (string-append poet-maybe-with-composer ", " year_text) poet-maybe-with-composer))
(composer-with-year (if (and composer year_melody) (string-append composer ", " year_melody) composer)) (composer-with-year (if (and composer year_melody) (string-append composer ", " year_melody) composer))
(concat-markupped-strings (lambda (text)
(ly:regex-replace (ly:make-regex "(\\S+)(\\\\\\w+(?:\\s+\\[^\\{\\s]*|\\s*\\{[^\\}]*\\}))(\\S*)") text "\\concat {" 1 "\\line {" 2 "}" 3 "}")))
(string-with-paragraphs->markuplist (lambda (prefix text) (string-with-paragraphs->markuplist (lambda (prefix text)
(if text (if text
(apply append (apply append
(map (map
(lambda (paragraph) (lambda (paragraph)
(make-wordwrap-internal-markup-list #t (make-wordwrap-internal-markup-list #t
#{ \markuplist { $(ly:parser-include-string paragraph) } #})) #{ \markuplist { $(ly:parser-include-string (concat-markupped-strings paragraph)) } #}))
(ly:regex-split (ly:make-regex "\r?\n[ \t\r\n]*\n[ \t\r\n]*") (string-append prefix text)))) (ly:regex-split (ly:make-regex "\r?\n[ \t\r\n]*\n[ \t\r\n]*") (string-append prefix text))))
'()))) '())))
(poet-and-composer-markup-list (poet-and-composer-markup-list
@@ -75,4 +187,4 @@
))))) )))))
(make-null-markup) (make-null-markup)
) )
} }
+2 -1
View File
@@ -16,9 +16,10 @@ songTocColumns = 3
globalSize = 15 globalSize = 15
lyricSize = 1.6 lyricSize = 1.6
stanzaFormat = "~a." stanzaFormat = "~a."
romanStanzaFormat = "~@r."
refString = "Ref.:" refString = "Ref.:"
refStringWithNumbers = "Ref. ~a:" refStringWithNumbers = "Ref. ~a:"
bridgeString = "Bridge:"
bridgeStringWithNumbers = "Bridge ~a:"
% hübsche Wiederholungszeichen für den Liedtext % hübsche Wiederholungszeichen für den Liedtext
repStart = "𝄆" repStart = "𝄆"
repStop = "𝄇" repStop = "𝄇"
+157
View File
@@ -0,0 +1,157 @@
%% Mehrere Lieder in einer Liederdatei (z.B. zwei Lieder auf einer Seite)
%%
%% Das erste Lied ist das Hauptlied (HEADER), alle weiteren werden als
%% eingebettete Lieder angemeldet. Eingebettete Lieder bekommen eigene
%% Eintraege im Inhaltsverzeichnis, in den Kategorie-, Autoren- und
%% Kapitelverzeichnissen, im PDF-Inhaltsverzeichnis, in der toc.csv und
%% eine eigene Liednummer. Im Footer steht die Songinfo des letzten
%% eingebetteten Lieds (abschaltbar mit footersong = ##f im HEADER bzw. mit
%% footersong = \andereslied umstellbar), die Songinfo des Hauptlieds wird
%% mit \songinfo-of selbst platziert.
%%
%% Beispiel:
%%
%% \include "../../lilypond-song-includes/liedbausteine/lied_a.ly"
%% liedA = \captureSong
%% \include "../../lilypond-song-includes/liedbausteine/lied_b.ly"
%% liedB = \captureSong
%%
%% TEXT = \markuplist {
%% \songinfo-of \liedA
%% \vspace #2
%% \embedded-song-title \liedB
%% \vspace #.5
%% \score { \songMusic \liedB \layout { \LAYOUT } }
%% \with-song \liedB {
%% \chordlyrics \secondVerse
%% }
%% }
%%
%% \restoreSong \liedA
%% \embedSong \liedB
%% \include "public_includes/layout_bottom.ily"
%%
%% \captureSong sichert den Header (basicSongInfo) und die Variablen aus
%% captured-song-variable-names, damit das naechste \include sie nicht
%% ueberschreibt. Das Ergebnis ist ein normales Header-Modul, es kann also
%% auch in \header { \liedA } verwendet werden.
%%
%% \restoreSong setzt basicSongInfo, HEADER und diese Variablen zurueck,
%% TEXT aber nicht. TEXT also vor \restoreSong schreiben, solange darin noch
%% Variablen des zuletzt eingebundenen Lieds (\secondVerse usw.) stehen.
%%
%% Ohne \with-song beziehen sich Strophen mit Akkorden auf das Hauptlied.
%%
%% Alle Verzeichniseintraege zeigen auf die erste Seite des Hauptlieds.
#(define captured-song-variable-names '(MUSIC global firstVoice verseChords))
#(define (song-variable song name)
(assq-ref (module-ref song 'captured-song-variables '()) name))
#(define (extract-and-check-vars-from-module headermodule varlist)
(let* ((headervars (if (module? headermodule) (hash-map->list cons (struct-ref headermodule 0)) '()))
(extract-var-and-check (lambda (headervar)
(let* ((variableref (assoc-ref headervars headervar))
(extracted (if variableref (variable-ref variableref) #f)))
(if (and extracted (not (and (string? extracted) (string-null? extracted)))) extracted #f)))))
(map (lambda (varsymbol)
(cons varsymbol (extract-var-and-check varsymbol))
) varlist)))
% Text des PDF-Lesezeichens eines Lieds, #f wenn es keins bekommt.
% Gleiche Regel wie in build-full-title.
#(define (song-pdf-bookmark-title headermodule)
(let* ((vars (extract-and-check-vars-from-module headermodule '(title starttext)))
(title (assq-ref vars 'title))
(starttext (assq-ref vars 'starttext))
(as-string (lambda (m) (if (markup? m) (markup->string m) ""))))
(cond ((and title starttext) (string-append (as-string starttext) " | " (as-string title)))
(title (as-string title))
(starttext (string-append (as-string starttext) " | "))
(else #f))))
#(define (embedded-song-list songs)
(if (list? songs) (filter module? songs) '()))
#(define (embedded-songs-of-header headermodule)
(if (module? headermodule)
(embedded-song-list (module-ref headermodule 'embeddedsongs '()))
'()))
% Ersetzt alle header:*-Properties durch die Felder aus headermodule, damit
% keine Felder des Hauptlieds in das andere Lied durchsickern.
#(define (header-module->props headermodule props)
(let ((header-key? (lambda (entry)
(and (pair? entry) (symbol? (car entry))
(string-prefix? "header:" (symbol->string (car entry)))))))
(cons
(map (lambda (kv) (cons (symbol-append 'header: (car kv)) (cdr kv)))
(ly:module->alist headermodule))
(map (lambda (alist) (remove header-key? alist)) props))))
captureSong =
#(define-scheme-function () ()
(let ((song (make-module)))
(ly:module-copy song basicSongInfo)
(module-define! song 'captured-song-variables
(filter-map
(lambda (name)
(let ((value (ly:parser-lookup name)))
(and (not (null? value)) (cons name value))))
captured-song-variable-names))
song))
% Stellt basicSongInfo, HEADER und die gesicherten Variablen eines Lieds
% wieder her, als waere es das zuletzt eingebundene.
restoreSong =
#(define-void-function (song) (module?)
(for-each
(lambda (kv) (ly:parser-define! (car kv) (cdr kv)))
(module-ref song 'captured-song-variables '()))
(ly:parser-define! 'basicSongInfo song)
(ly:parser-define! 'HEADER #{ \bookpart { \header { $song } } #}))
embedSong =
#(define-void-function (song) (module?)
(set! EMBEDDED_SONGS (append EMBEDDED_SONGS (list song))))
songMusic =
#(define-music-function (song) (module?)
(let ((music (song-variable song 'MUSIC)))
(if (ly:music? music) music (make-music 'SequentialMusic))))
% Strophen, \fromproperty #'header:... usw. beziehen sich innerhalb auf das
% angegebene Lied. Die Transposition des Hauptlieds wird nicht uebernommen.
#(define-markup-list-command (with-song layout props song args) (module? markup-list?)
(let* ((music-or-empty (lambda (name)
(let ((music (song-variable song name)))
(if (ly:music? music) music (make-music 'SequentialMusic)))))
(verseChords (music-or-empty 'verseChords))
(global (music-or-empty 'global))
(firstVoice (music-or-empty 'firstVoice)))
(interpret-markup-list layout
(prepend-alist-chain 'verse-chords #{ \chords { $verseChords } #}
(prepend-alist-chain 'verse-reference-voice #{ $global $firstVoice #}
(prepend-alist-chain 'transposition (cons #f #f)
(header-module->props song props))))
args)))
#(define-markup-command (songinfo-of layout props song) (module?)
(interpret-markup layout (header-module->props song props)
(make-fractional-line-width-markup (make-songinfo-content-markup))))
#(define-markup-command (embedded-song-title layout props song) (module?)
(interpret-markup layout (header-module->props song props)
(make-fill-line-markup (list (ly:output-def-lookup layout 'defaultTitleMarkup)))))
% PDF-Lesezeichen der eingebetteten Lieder, wird von build-full-title direkt
% nach dem Lesezeichen des Hauptlieds ausgegeben.
#(define-markup-command (embedded-songs-to-pdf-toc layout props) ()
(apply ly:stencil-add
(cons empty-stencil
(filter-map
(lambda (song)
(let ((bookmark (song-pdf-bookmark-title song)))
(and bookmark (make-pdf-toc-stencil bookmark 0))))
(embedded-song-list (chain-assoc-get 'header:embeddedsongs props '()))))))
@@ -6,10 +6,20 @@
#(define-markup-command (customEps layout props ysize filename)(number? string?) #(define-markup-command (customEps layout props ysize filename)(number? string?)
#:properties ((songfilename "")) #:properties ((songfilename ""))
(interpret-markup layout props (interpret-markup layout props
(let ((defaulttitlemarkup (ly:output-def-lookup layout 'defaultTitleMarkup)) (let* ((defaulttitlemarkup (ly:output-def-lookup layout 'defaultTitleMarkup))
(filepath (if (string-null? songfilename) ;; Determine the song directory to resolve the EPS relative to.
filename ;; In TEXT the name arrives via the markup props (\setsongfilename),
(ly:format "~a/~a/~a" songPath songfilename filename)))) ;; but inside MUSIC (e.g. \mark) the props do not carry it, so we
;; fall back to the value stored in the score's \layout block.
(layout-songfilename (ly:output-def-lookup layout 'songfilename #f))
(songdir (cond ((not (string-null? songfilename)) songfilename)
((and (string? layout-songfilename)
(not (string-null? layout-songfilename)))
layout-songfilename)
(else #f)))
(filepath (if songdir
(ly:format "~a/~a/~a" songPath songdir filename)
filename)))
(if (file-exists? filepath) (if (file-exists? filepath)
(make-epsfile-markup Y ysize filepath) (make-epsfile-markup Y ysize filepath)
(if defaulttitlemarkup (if defaulttitlemarkup
+58 -98
View File
@@ -30,7 +30,11 @@
(lambda (a b) (< (cadr a) (cadr b)))) (lambda (a b) (< (cadr a) (cadr b))))
(list))) (list)))
#(define-markup-command (print-songinfo layout props) () #(define (join-present items joiner)
(string-join (filter (lambda (item) (and (string? item) (not (string-null? (string-trim-both item))))) items) joiner))
% Songinfo aus den header:*-Properties, ohne Pruefung auf die letzte Seite.
#(define-markup-command (songinfo-content layout props) ()
(define (songinfo-from songId key) (define (songinfo-from songId key)
(let ((song (if (defined? 'SONG_DATA) (assoc-ref SONG_DATA songId) #f))) (let ((song (if (defined? 'SONG_DATA) (assoc-ref SONG_DATA songId) #f)))
(if song (if song
@@ -74,11 +78,7 @@
(define (render-contribution-group contributionPrefix authorIds) (define (render-contribution-group contributionPrefix authorIds)
(if (null? authorIds) (if (null? authorIds)
"" ""
(string-append contributionPrefix " " (string-join (format-authors authorIds) ", "))) (string-append contributionPrefix " " ((ly:output-def-lookup layout 'author-joiner) (format-authors authorIds))))
)
(define (join-present items joiner)
(string-join (filter (lambda (item) (and (string? item) (not (string-null? (string-trim-both item))))) items) joiner)
) )
(define (render-partial-contribution-group prefixLookup authorData) (define (render-partial-contribution-group prefixLookup authorData)
@@ -94,99 +94,44 @@
(define (poet-and-composer-from-authors authors) (define (poet-and-composer-from-authors authors)
(if authors (if authors
(let ( ((ly:output-def-lookup layout 'authorContributionFormat)
(poetIds (find-author-ids-by 'text authors)) render-contribution-group
(translatorIds (find-author-ids-by 'translation authors)) render-partial-contribution-group
(versePoetData (find-author-id-with-part-numbers 'verse authors)) #:poetIds (find-author-ids-by 'text authors)
(composerIds (find-author-ids-by 'melody authors)) #:translatorIds (find-author-ids-by 'translation authors)
(verseComposerData (find-author-id-with-part-numbers 'meloverse authors)) #:versePoetData (find-author-id-with-part-numbers 'verse authors)
(voiceComposerData (find-author-id-with-part-numbers 'voice authors)) #:composerIds (find-author-ids-by 'melody authors)
(compositionIds (find-author-ids-by 'composition authors)) #:verseComposerData (find-author-id-with-part-numbers 'meloverse authors)
(adaptionTextIds (find-author-ids-by 'adaption_text authors)) #:refComposerIds (find-author-ids-by 'meloref authors)
(adaptionMusicIds (find-author-ids-by 'adaption_music authors)) #:voiceComposerData (find-author-id-with-part-numbers 'voice authors)
(bridgeIds (find-author-ids-by 'bridge authors)) #:compositionIds (find-author-ids-by 'composition authors)
(interludeIds (find-author-ids-by 'interlude authors)) #:adaptionTextIds (find-author-ids-by 'adaption_text authors)
(year_text (chain-assoc-get 'header:year_text props #f)) #:adaptionMusicIds (find-author-ids-by 'adaption_music authors)
(year_translation (chain-assoc-get 'header:year_translation props #f)) #:bridgeIds (find-author-ids-by 'bridge authors)
(year_melody (chain-assoc-get 'header:year_melody props #f)) #:interludeIds (find-author-ids-by 'interlude authors)
(year_composition (chain-assoc-get 'header:year_composition props #f)) #:year_text (chain-assoc-get 'header:year_text props #f)
(year_adaption_text (chain-assoc-get 'header:year_adaption_text props #f)) #:year_translation (chain-assoc-get 'header:year_translation props #f)
(year_adaption_music (chain-assoc-get 'header:year_adaption_music props #f)) #:year_melody (chain-assoc-get 'header:year_melody props #f)
) #:year_melody_meloref (chain-assoc-get 'header:year_melody_meloref props #f)
(if (and #:year_composition (chain-assoc-get 'header:year_composition props #f)
(equal? poetIds composerIds) #:year_adaption_text (chain-assoc-get 'header:year_adaption_text props #f)
(null? translatorIds) #:year_adaption_music (chain-assoc-get 'header:year_adaption_music props #f)
(null? versePoetData) #:poetAndComposerEqualPrefix (ly:output-def-lookup layout 'poetAndComposerEqualPrefix)
(null? verseComposerData) #:poetPrefix (ly:output-def-lookup layout 'poetPrefix)
(null? voiceComposerData) #:composerPrefix (ly:output-def-lookup layout 'composerPrefix)
(null? compositionIds) #:translationAuthorPrefix (ly:output-def-lookup layout 'translationAuthorPrefix)
(null? adaptionTextIds) #:pronunciationPrefix (ly:output-def-lookup layout 'pronunciationPrefix)
(null? adaptionMusicIds) #:compositionPrefix (ly:output-def-lookup layout 'compositionPrefix)
(null? bridgeIds) #:adaptionTextPrefix (ly:output-def-lookup layout 'adaptionTextPrefix)
(null? interludeIds)) #:adaptionMusicPrefix (ly:output-def-lookup layout 'adaptionMusicPrefix)
(list #:bridgePrefix (ly:output-def-lookup layout 'bridgePrefix)
(join-present (list #:interludePrefix (ly:output-def-lookup layout 'interludePrefix)
(render-contribution-group (ly:output-def-lookup layout 'poetAndComposerEqualPrefix) poetIds) #:refPrefix (ly:output-def-lookup layout 'refPrefix))
(if (equal? year_text year_melody) year_text (join-present (list year_text year_melody) "/"))
) ", ")
#f)
(list
(if (and (null? poetIds) (null? versePoetData) (null? translatorIds)) #f
(string-append
(ly:output-def-lookup layout 'poetPrefix)
" "
(join-present (list
(join-present (list
(render-contribution-group "" poetIds)
year_text
) ", ")
(render-partial-contribution-group 'versePrefix versePoetData)
(join-present (list
(render-contribution-group (ly:output-def-lookup layout 'translationAuthorPrefix) translatorIds)
year_translation
) ", ")
(join-present (list
(render-contribution-group (ly:output-def-lookup layout 'adaptionTextPrefix) adaptionTextIds)
year_adaption_text
) ", ")
) "; ")
))
(if (and
(null? composerIds)
(null? compositionIds)
(null? adaptionMusicIds)
(null? verseComposerData)
(null? voiceComposerData)
(null? bridgeIds)
(null? interludeIds)) #f
(string-append
(ly:output-def-lookup layout 'composerPrefix)
" "
(join-present (list
(join-present (list
(render-contribution-group "" composerIds)
year_melody
) ", ")
(render-partial-contribution-group 'versePrefix verseComposerData)
(render-partial-contribution-group 'voicePrefix voiceComposerData)
(join-present (list
(render-contribution-group (ly:output-def-lookup layout 'compositionPrefix) compositionIds)
year_composition
) ", ")
(join-present (list
(render-contribution-group (ly:output-def-lookup layout 'adaptionMusicPrefix) adaptionMusicIds)
year_adaption_music
) ", ")
(render-contribution-group (ly:output-def-lookup layout 'bridgePrefix) bridgeIds)
(render-contribution-group (ly:output-def-lookup layout 'interludePrefix) interludeIds)
) "; ")
)))))
(list #f #f) (list #f #f)
) )
) )
(interpret-markup layout props (interpret-markup layout props
(if (chain-assoc-get 'page:is-bookpart-last-page props #f)
(let* ((authors (chain-assoc-get 'header:authors props #f)) (let* ((authors (chain-assoc-get 'header:authors props #f))
(poet-and-composers (poet-and-composer-from-authors authors)) (poet-and-composers (poet-and-composer-from-authors authors))
(songId (chain-assoc-get 'header:songId props #f)) (songId (chain-assoc-get 'header:songId props #f))
@@ -200,7 +145,7 @@
(translation (chain-assoc-get 'header:translation props #f)) (translation (chain-assoc-get 'header:translation props #f))
(pronunciation (chain-assoc-get 'header:pronunciation props #f)) (pronunciation (chain-assoc-get 'header:pronunciation props #f))
(year_text (if (string? (car poet-and-composers)) #f (chain-assoc-get 'header:year_text props #f))) (year_text (if (string? (car poet-and-composers)) #f (chain-assoc-get 'header:year_text props #f)))
(year_melody (if (string? (car poet-and-composers)) #f (chain-assoc-get 'header:year_melody props #f)))) (year_melody (if (string? (cadr poet-and-composers)) #f (chain-assoc-get 'header:year_melody props #f))))
(markup (markup
#:override (cons 'songinfo:poet-maybe-with-composer #:override (cons 'songinfo:poet-maybe-with-composer
(if (and poet-maybe-with-composer (not (and (string? poet-maybe-with-composer) (string-null? poet-maybe-with-composer)))) poet-maybe-with-composer #f)) (if (and poet-maybe-with-composer (not (and (string? poet-maybe-with-composer) (string-null? poet-maybe-with-composer)))) poet-maybe-with-composer #f))
@@ -222,10 +167,25 @@
#:fontsize songInfoFontSize #:fontsize songInfoFontSize
#:sans #:sans
(ly:output-def-lookup layout 'songinfoMarkup) (ly:output-def-lookup layout 'songinfoMarkup)
))) ))))
(make-null-markup)))
) )
% Songinfo im Footer, nur auf der letzten Seite des Bookparts. Gibt es
% eingebettete Lieder (siehe embedded_songs.ily), steht hier die Songinfo des
% letzten eingebetteten Lieds, ausser im Header ist footersong gesetzt
% (##f = Hauptlied, oder ein mit \captureSong gesichertes Lied).
#(define-markup-command (print-songinfo layout props) ()
(if (chain-assoc-get 'page:is-bookpart-last-page props #f)
(let* ((footersong (chain-assoc-get 'header:footersong props 'auto))
(embedded (embedded-song-list (chain-assoc-get 'header:embeddedsongs props '())))
(song (if (eq? footersong 'auto)
(and (pair? embedded) (last embedded))
footersong)))
(interpret-markup layout
(if (module? song) (header-module->props song props) props)
(make-songinfo-content-markup)))
(interpret-markup layout props (make-null-markup))))
#(define-markup-command (print-pagenumber layout props)() #(define-markup-command (print-pagenumber layout props)()
(let ((label (chain-assoc-get 'header:myindexlabel props #f))) (let ((label (chain-assoc-get 'header:myindexlabel props #f)))
(interpret-markup layout props (interpret-markup layout props
@@ -270,4 +230,4 @@
\line { \page-number-to-pdf-label \null } \line { \page-number-to-pdf-label \null }
} }
} }
} }
@@ -0,0 +1,16 @@
% We have to record the tag groups for markup, so we use the right tag groups during markup interpretiton.
recordedTagGroups = #'()
tagGroup =
#(define-void-function (tags) (symbol-list?)
(let ((err (define-tag-group tags)))
(if err (ly:parser-error err (*location*))
(set! recordedTagGroups (cons tags recordedTagGroups)))))
#(define-markup-command (handle-tag-groups layout props recorded-groups m) (list? markup?)
(resetTagGroups)
(for-each
(lambda (group)
(define-tag-group group))
recorded-groups)
(interpret-markup layout props m))
+4 -4
View File
@@ -1,4 +1,4 @@
swing = \mark \markup { swing = \textMark \markup {
\line \general-align #Y #DOWN { \line \general-align #Y #DOWN {
\score { \score {
\new Staff \with { \new Staff \with {
@@ -47,7 +47,7 @@ swing = \mark \markup {
} }
} }
swingOff = \mark \markup { swingOff = \textMark \markup {
\line \general-align #Y #DOWN { \line \general-align #Y #DOWN {
\score { \score {
\new Staff \with { \new Staff \with {
@@ -99,7 +99,7 @@ swingOff = \mark \markup {
\include "swing.ly" \include "swing.ly"
swingMusic = swingMusic =
#(define-music-function (parser location music) (ly:music?) #(define-music-function (music) (ly:music?)
(define (partial-duration-length m) (define (partial-duration-length m)
(let ((name (ly:music-property m 'name)) (let ((name (ly:music-property m 'name))
(es (ly:music-property m 'elements)) (es (ly:music-property m 'elements))
@@ -118,4 +118,4 @@ swingMusic =
#{ #{
\swing \swing
\applySwingWithOffset 8 #'(2 1) #(partial-duration-length music) #music \applySwingWithOffset 8 #'(2 1) #(partial-duration-length music) #music
#}) #})
@@ -1,6 +1,5 @@
#(define-markup-command (bookTitleMarkupCustom layout props)() #(define-markup-command (bookTitleMarkupCustom layout props)()
(interpret-markup layout (interpret-markup layout props
(prepend-alist-chain 'songfilename (chain-assoc-get 'header:songfilename props "") props)
(make-column-markup (make-column-markup
(list (list
(make-vspace-markup (chain-assoc-get 'header:titletopspace props 0)) (make-vspace-markup (chain-assoc-get 'header:titletopspace props 0))
@@ -27,34 +26,60 @@
#(define pdf-encode (@@ (lily framework-ps) pdf-encode)) #(define pdf-encode (@@ (lily framework-ps) pdf-encode))
% PDF tags % PDF tags
#(define-markup-command (title-to-pdf-toc layout props title) (string?) % Erzeugt ein PDF-Lesezeichen (Outline-Eintrag) auf der aktuellen Seite.
% count = Anzahl der direkten Unterpunkte, die (in Seitenreihenfolge) direkt
% nachfolgen. 0 = Blatt-Eintrag (kein /Count), >0 = aufgeklappt,
% <0 = zugeklappt (Betrag = Anzahl direkter Kinder).
#(define (make-pdf-toc-stencil title count)
(if (string-null? title) (if (string-null? title)
empty-stencil empty-stencil
(ly:make-stencil (ly:make-stencil
(list 'embedded-ps (list 'embedded-ps
(ly:format (ly:format
"[/Action /GoTo /View [/XYZ -4 currentpagedevice /PageSize get 1 get 4 add null] /Title (~a) /OUT pdfmark" (pdf-encode title))) "[~a/Action /GoTo /View [/XYZ -4 currentpagedevice /PageSize get 1 get 4 add null] /Title (~a) /OUT pdfmark"
(if (= count 0) "" (ly:format "/Count ~a " count))
(pdf-encode title)))
empty-interval empty-interval empty-interval empty-interval
;'(0 . 0) '(0 . 0) ;'(0 . 0) '(0 . 0)
))) )))
#(define-markup-command (title-with-category-images layout props right)(boolean?) % Einzelner (Blatt-)Eintrag im PDF-Inhaltsverzeichnis.
(interpret-markup layout props #(define-markup-command (title-to-pdf-toc layout props title) (string?)
(make-pdf-toc-stencil title 0))
% Kapitel-Eintrag mit verschachtelten Unterpunkten.
% count = Anzahl der direkt nachfolgenden Einträge, die diesem Kapitel
% untergeordnet werden sollen (positiv = aufgeklappt, negativ = zugeklappt).
#(define-markup-command (chapter-to-pdf-toc layout props count title) (integer? string?)
(make-pdf-toc-stencil title count))
#(define-markup-command (build-full-title layout props right)(boolean?)
(interpret-markup layout (prepend-alist-chain 'songfilename (chain-assoc-get 'header:songfilename props "") props)
(let* ((title (chain-assoc-get 'header:title props "")) (let* ((title (chain-assoc-get 'header:title props ""))
(starttext (chain-assoc-get 'header:starttext props #f)) (starttext (chain-assoc-get 'header:starttext props #f))
(pdfbookmark (if starttext (string-append starttext " | " title) title))) (pdfbookmark (if starttext (string-append starttext " | " title) title))
(chaptertitle (chain-assoc-get 'header:chaptertitle props #f))
(chaptercount (chain-assoc-get 'header:chaptercount props 0))
(title-markup (ly:output-def-lookup layout (if right 'oddTitleLineMarkup 'evenTitleLineMarkup))))
(if title (if title
(if right ;; Ist dieses Lied das erste eines Kapitels, wird der Kapitel-Eintrag
#{\markup { \title-to-pdf-toc #pdfbookmark \fill-line \general-align #Y #UP { \null \bookTitleMarkupCustom \category-images } } #} ;; unmittelbar vor dem Lied-Eintrag ausgegeben, damit die pdfmark-/OUT-
#{\markup { \title-to-pdf-toc #pdfbookmark \fill-line \general-align #Y #UP { \category-images \bookTitleMarkupCustom \null } } #}) ;; Reihenfolge (Elternteil vor Kindern) im PDF-Stream garantiert stimmt.
#{ \markup { " " } #}) ;; Eingebettete Lieder (embedded_songs.ily) folgen direkt nach dem Lied.
(if (and (string? chaptertitle) (not (string-null? chaptertitle)))
(markup #:chapter-to-pdf-toc chaptercount chaptertitle
#:title-to-pdf-toc pdfbookmark #:embedded-songs-to-pdf-toc title-markup)
(markup #:title-to-pdf-toc pdfbookmark #:embedded-songs-to-pdf-toc title-markup))
make-null-markup)
))) )))
\paper { \paper {
bookTitleMarkup = \markup \null bookTitleMarkup = \markup \null
scoreTitleMarkup = \markup \null scoreTitleMarkup = \markup \null
oddHeaderMarkup = \markup { \if \on-first-page-of-part \title-with-category-images ##t } oddHeaderMarkup = \markup { \if \on-first-page-of-part \build-full-title ##t }
evenHeaderMarkup = \markup { \if \on-first-page-of-part \title-with-category-images ##f } evenHeaderMarkup = \markup { \if \on-first-page-of-part \build-full-title ##f }
oddTitleLineMarkup = \markup { \fill-line \general-align #Y #UP { \null \bookTitleMarkupCustom \category-images } }
evenTitleLineMarkup = \markup { \fill-line \general-align #Y #UP { \category-images \bookTitleMarkupCustom \null } }
defaultTitleMarkup = \markup { defaultTitleMarkup = \markup {
\override #'(baseline-skip . 3.5) \override #'(baseline-skip . 3.5)
\center-column { \center-column {
@@ -63,4 +88,4 @@
\smaller \bold \fromproperty #'header:subsubtitle \smaller \bold \fromproperty #'header:subsubtitle
} }
} }
} }
+6 -1
View File
@@ -2,7 +2,12 @@ TRANSPOSITION = #(cons #f #f)
transposeGlobal = transposeGlobal =
#(define-void-function (from to) (ly:pitch? ly:pitch?) #(define-void-function (from to) (ly:pitch? ly:pitch?)
(set! TRANSPOSITION (cons from to))) (if (not (car TRANSPOSITION))
(set! TRANSPOSITION (cons from to))
(let ((current_to (cdr TRANSPOSITION))
(interval (ly:pitch-diff to from)))
(set! TRANSPOSITION (cons (car TRANSPOSITION)
(ly:pitch-transpose current_to interval))))))
transposable = transposable =
#(define-music-function (fromto music) (pair? ly:music?) #(define-music-function (fromto music) (pair? ly:music?)
+158 -41
View File
@@ -60,19 +60,20 @@
% Text über Text mittig darstellen % Text über Text mittig darstellen
#(define-markup-command (textup layout props text uptext) (markup? markup?) #(define-markup-command (textup layout props text uptext) (markup? markup?)
#:properties ((verselayout generalLayout)
(verse-text-chord-distance songTextChordDistance))
"Markup über Text mittig darstellen." "Markup über Text mittig darstellen."
(let ((verselayout (chain-assoc-get 'verselayout props generalLayout)))
(interpret-markup layout props (interpret-markup layout props
#{\markup { #{\markup {
\size-box-to-box-style-dependent ##t ##f \size-box-to-box-style-dependent ##t ##f
\general-align #X #LEFT \override #`(direction . ,UP) \override #'(baseline-skip . 1.0) \dir-column \chord-alignment-style-dependent { \general-align #X #LEFT \override #`(direction . ,UP) \override #'(baseline-skip . 1) \dir-column \chord-alignment-style-dependent {
\pad-to-box #'(0 . 0) #'(0 . 2.0) { #text } \pad-to-box #'(0 . 0) #`(0 . ,(- verse-text-chord-distance 0.8)) { #text }
\size-box-to-box ##f ##t #uptext \score { \chords { g4:m a } \layout { \verselayout } } \size-box-to-box ##f ##t #uptext \score { \chords { g4:m a } \layout { $verselayout #(customized-layout verselayout) } }
} }
#text #text
} }
#} #}
))) ))
#(define-markup-command (anchor-x-between layout props arga argb) #(define-markup-command (anchor-x-between layout props arga argb)
(markup? markup?) (markup? markup?)
@@ -82,16 +83,15 @@
(ly:stencil-aligned-to m X (- (/ (* la 2) l) 1)) (ly:stencil-aligned-to m X (- (/ (* la 2) l) 1))
)) ))
#(define-markup-command (stanza-raw layout props arg) #(define-markup-command (stanza-raw layout props arg) (string-or-music?)
(string-or-music?) #:properties ((verselayout generalLayout))
(let ((verselayout (chain-assoc-get 'verselayout props generalLayout)))
(interpret-markup layout props (interpret-markup layout props
(if (and (string? arg) (string-null? arg)) (if (and (string? arg) (string-null? arg))
" " " "
#{\markup #{\markup
\score { \new Lyrics { \lyricmode { #(if (ly:music? arg) arg #{ \set stanza = #arg #}) "" } } \layout { \verselayout } } \score { \new Lyrics { \lyricmode { #(if (ly:music? arg) arg #{ \stanza #arg #}) "" } } \layout { $verselayout #(customized-layout verselayout) } }
#} #}
)))) )))
#(define-markup-command (stanza layout props arg) #(define-markup-command (stanza layout props arg)
(string-or-music?) (string-or-music?)
@@ -141,7 +141,7 @@
(make-wrap-newline-markup (make-wrap-newline-markup
(ly:regex-replace (ly:make-regex "\\(( *)([^,()]*)( *),([^)]*)\\)") (ly:regex-replace (ly:make-regex "\\(( *)([^,()]*)( *),([^)]*)\\)")
(ly:regex-replace (ly:make-regex "(([^ \n]*\\([^()]*,[^()]+\\)[^ \n(]*)+)") (handle-custom-newlines custom-verse-breaks verse) " \\concat { " 1 " } ") (ly:regex-replace (ly:make-regex "(([^ \n]*\\([^()]*,[^()]+\\)[^ \n(]*)+)") (handle-custom-newlines custom-verse-breaks verse) " \\concat { " 1 " } ")
"\\textup \\line { \"" 1 "\" " 2 " \"" 3 "\" } \\score { " transp " \\chords { s4 " 4 " } \\layout { \\verselayout } }") "\\textup \\line { \"" 1 "\" " 2 " \"" 3 "\" } \\score { " transp " \\chords { s4 " 4 " } \\layout { $verselayout #(customized-layout verselayout) } }")
) )
)))) ))))
@@ -203,23 +203,9 @@
#(define-markup-command (pad-left layout props amount arg) #(define-markup-command (pad-left layout props amount arg)
(number? markup?) (number? markup?)
(let* ((m (interpret-markup layout props arg))
(x (ly:stencil-extent m X))
(y (ly:stencil-extent m Y)))
(ly:stencil-translate (ly:stencil-translate
(ly:make-stencil (ly:stencil-expr m) (interpret-markup layout props (make-pad-x-left-markup amount arg))
(cons (- (car x) amount) (cdr x)) `(,amount . 0)))
y)
`(,amount . 0))))
#(define-markup-command (pad-right layout props amount arg)
(number? markup?)
(let* ((m (interpret-markup layout props arg))
(x (ly:stencil-extent m X))
(y (ly:stencil-extent m Y)))
(ly:make-stencil (ly:stencil-expr m)
(cons (car x) (+ (cdr x) amount))
y)))
#(define-markup-command (score-equal-height-with-indents layout props lines) #(define-markup-command (score-equal-height-with-indents layout props lines)
(markup-list?) (markup-list?)
@@ -250,9 +236,145 @@
(let ((text (ly:grob-property grob 'text))) (let ((text (ly:grob-property grob 'text)))
(grob-interpret-markup grob (if (string? text) (grob-interpret-markup grob (if (string? text)
(make-pad-right-markup -0.1 (make-tied-lyric-markup text)) (make-pad-x-right-markup -0.1 (make-tied-lyric-markup text))
text)))) text))))
Chord_lyrics_spacing_engraver =
#(lambda (ctx)
(let ((last-lyric-syllable #f)
(lyric-width-since-last-chord 0)
(music-columns-for-last-syllable 0)
(last-printed-chord #f)
(chord-width-since-last-lyric 0)
(lyrics-seen-since-break #f)
(have-a-rest #f)
(stanza #f)
; Akkord auf einer Skip-Silbe "_" nach Wortende soll über die folgende Silbe
(word-continues #f)
(continuation-this-step #f)
(lyric-skip-this-step #f)
(syllable-this-step #f)
(chord-this-step #f)
(chord-on-lyric-skip #f)
(place-at-right-edge
(lambda (grob anchor padding)
(let ((anchor-width (interval-length (ly:grob-extent anchor anchor X))))
(ly:grob-set-parent! grob X anchor)
(ly:grob-set-property! grob 'X-offset (+ padding anchor-width))
))))
(make-engraver
((start-translation-timestep engraver)
(set! continuation-this-step #f)
(set! lyric-skip-this-step #f)
(set! syllable-this-step #f)
(set! chord-this-step #f)
)
((stop-translation-timestep engraver)
(if (and chord-on-lyric-skip (not (eq? chord-on-lyric-skip chord-this-step)))
(begin
(if (and syllable-this-step (not chord-this-step))
(begin
(ly:grob-set-parent! chord-on-lyric-skip X syllable-this-step)
(ly:grob-set-property! chord-on-lyric-skip 'X-offset 0)
(ly:grob-set-property! chord-on-lyric-skip 'extra-spacing-width '(+inf.0 . -inf.0))
(set! lyric-width-since-last-chord (interval-length (ly:grob-extent syllable-this-step syllable-this-step X)))))
(set! chord-on-lyric-skip #f)))
(if syllable-this-step
(set! word-continues continuation-this-step))
)
(listeners
((multi-measure-rest-event engraver event)
(set! have-a-rest #t)
)
((rest-event engraver event)
(set! have-a-rest #t)
)
((hyphen-event engraver event)
(set! continuation-this-step #t)
)
((extender-event engraver event)
(set! continuation-this-step #t)
)
((lyric-event engraver event)
(set! have-a-rest #f)
; "_" wird zu " " und erzeugt keine LyricText
(if (equal? (ly:event-property event 'text) " ")
(begin
(set! lyric-skip-this-step #t)
(set! chord-on-lyric-skip #f)))
(set! music-columns-for-last-syllable 0)
)
((break-event engraver event)
(set! last-lyric-syllable #f)
(set! lyric-width-since-last-chord 0)
(set! music-columns-for-last-syllable 0)
(set! last-printed-chord #f)
(set! chord-width-since-last-lyric 0)
(set! lyrics-seen-since-break #f)
(set! chord-on-lyric-skip #f)
))
(acknowledgers
((musical-paper-column-interface this-engraver grob source-engraver)
(set! music-columns-for-last-syllable (+ 1 music-columns-for-last-syllable))
)
((lyric-syllable-interface this-engraver grob source-engraver)
(let ((syllable-width (interval-length (ly:grob-extent grob grob X))))
(set! lyric-width-since-last-chord (+ lyric-width-since-last-chord syllable-width))
)
(if (> chord-width-since-last-lyric 0)
(if lyrics-seen-since-break
(ly:grob-set-property! grob 'extra-spacing-width
(cons (- chord-width-since-last-lyric) (cdr (ly:grob-property grob 'extra-spacing-width '(0 . 0)))))
(if last-printed-chord
(let ((gap-for-starting-rest 2.0))
(if stanza (ly:grob-set-property! stanza 'padding (+ 1 gap-for-starting-rest)))
(ly:grob-set-parent! grob X last-printed-chord)
(ly:grob-set-property! grob 'X-offset gap-for-starting-rest)
)))
)
(set! syllable-this-step grob)
(set! last-lyric-syllable grob)
(set! chord-width-since-last-lyric 0)
(set! lyrics-seen-since-break #t)
)
((chord-name-interface this-engraver grob source-engraver)
(if (not (and
(boolean? (ly:grob-property grob 'begin-of-line-visible))
(ly:grob-property grob 'begin-of-line-visible)
lyrics-seen-since-break))
(let* ((last-printed-chord-width (if last-printed-chord (interval-length (ly:grob-extent last-printed-chord last-printed-chord X)) 0))
(chord-overwidth (- last-printed-chord-width lyric-width-since-last-chord))
(chord-gap 0.5))
(if have-a-rest
(let ((chord-width (interval-length (ly:grob-extent grob grob X))))
(if last-lyric-syllable
(if (and last-printed-chord (> chord-overwidth 0))
(place-at-right-edge grob last-printed-chord chord-gap)
(place-at-right-edge grob last-lyric-syllable 0))
(if last-printed-chord
(place-at-right-edge grob last-printed-chord chord-gap)))
(set! chord-width-since-last-lyric (+ chord-width-since-last-lyric chord-width chord-gap))
))
(if (and last-lyric-syllable last-printed-chord (> chord-overwidth 0))
(ly:grob-set-property! last-lyric-syllable 'extra-spacing-width
(cons (car (ly:grob-property last-lyric-syllable 'extra-spacing-width '(0 . 0))) (+ chord-gap chord-overwidth)))
)
(set! lyric-width-since-last-chord (* (if last-lyric-syllable (interval-length (ly:grob-extent last-lyric-syllable last-lyric-syllable X)) 0) (- 1 (/ 1.0 music-columns-for-last-syllable))))
(set! chord-this-step grob)
(if (and lyric-skip-this-step (not have-a-rest) (not word-continues))
(set! chord-on-lyric-skip grob))
(set! last-printed-chord grob)
(set! last-lyric-syllable #f)
)
(ly:grob-set-property! grob 'X-extent '(+inf.0 . -inf.0))
)
)
((stanza-number-interface this-engraver grob source-engraver)
(set! stanza grob)
)
)
)))
#(define-markup-command (chordlyrics layout props lyrics) (ly:music?) #(define-markup-command (chordlyrics layout props lyrics) (ly:music?)
#:properties ((verse-chords #{#}) #:properties ((verse-chords #{#})
(verse-reference-voice #{#}) (verse-reference-voice #{#})
@@ -272,10 +394,8 @@
\new Lyrics \lyricsto "dummyvoice" { #lyrics } \new Lyrics \lyricsto "dummyvoice" { #lyrics }
>> >>
\layout { \layout {
\verselayout $verselayout
#(let #(customized-layout verselayout)
((custom-size (ly:output-def-lookup verselayout 'size #f)))
(if custom-size (layout-set-staff-size custom-size)))
ragged-right = ##t ragged-right = ##t
\context { \context {
\Lyrics \Lyrics
@@ -296,15 +416,20 @@
\context { \context {
\Score \Score
\override PaperColumn.keep-inside-line = ##f \override PaperColumn.keep-inside-line = ##f
% \override SpacingSpanner.strict-note-spacing = ##t % \override SpacingSpanner.strict-note-spacing = ##t
\override SpacingSpanner.uniform-stretching = ##t \override SpacingSpanner.uniform-stretching = ##t
\override SpacingSpanner.spacing-increment = 0 \override SpacingSpanner.spacing-increment = 0
% \override SpacingSpanner.packed-spacing = ##t
\consists \Chord_lyrics_spacing_engraver
% ChordPro engraver in Score context to collect all data
\consists \ChordPro_score_collector
\remove Bar_number_engraver \remove Bar_number_engraver
\remove Mark_engraver \remove Mark_engraver
\remove Jump_engraver \remove Jump_engraver
\remove Volta_engraver \remove Volta_engraver
\remove Parenthesis_engraver \remove Parenthesis_engraver
\remove Metronome_mark_engraver \remove Metronome_mark_engraver
\remove Text_mark_engraver
} }
\context { \context {
\Staff \Staff
@@ -328,14 +453,6 @@
\remove Note_heads_engraver \remove Note_heads_engraver
\remove Script_engraver \remove Script_engraver
} }
\context {
\NullVoice
\consists Rest_engraver
\omit Rest
\undo \omit NoteHead
\hide NoteHead
\override NoteHead.X-extent = #'(0 . 0)
}
} }
} }
} }
+168 -52
View File
@@ -119,7 +119,7 @@ width may require additional tweaking.)"
includeSong = includeSong =
#(define-void-function (parser location filename) (string?) #(define-void-function (filename) (string?)
#{ #{
\bookOutputName #filename \bookOutputName #filename
#} #}
@@ -130,32 +130,47 @@ includeSong =
(acons label additional-page-numbers additional-page-switch-label-list)) (acons label additional-page-numbers additional-page-switch-label-list))
(set! song-list (set! song-list
(acons (string->symbol filename) (acons (string->symbol filename)
(acons 'label label `(
(acons 'header HEADER (label . ,label)
(acons 'music MUSIC (header . ,HEADER)
(acons 'layout LAYOUT (music . ,MUSIC)
(acons 'text-pages (layout . ,LAYOUT)
(map (lambda (text) (text-pages . ,(map (lambda (text)
#{ \markuplist \setsongfilename $filename $text #}) #{ \markuplist \setsongfilename $filename $text #})
TEXT_PAGES) TEXT_PAGES))
'()))))) )
song-list)) song-list))
)) ))
blankpage = blankpage =
#(define-void-function (parser location) () #(define-void-function () ()
(set! song-list (set! song-list
(acons 'emptyPage (acons 'emptyPage
'() '()
song-list))) song-list)))
imagepage = imagepage =
#(define-void-function (parser location xsize filename) (number? string?) #(define-void-function (xsize filename) (number? string?)
(set! song-list (set! song-list
(acons 'imagePage (acons 'imagePage
(acons 'xsize xsize (acons 'filename filename '())) `((xsize . ,xsize)
(filename . ,filename))
song-list))) 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?) #(define-markup-command (pagecenter layout props stuff)(markup?)
(interpret-markup layout props (interpret-markup layout props
(let ((halfpaperheight (/ (ly:output-def-lookup layout 'paper-height) 2)) (let ((halfpaperheight (/ (ly:output-def-lookup layout 'paper-height) 2))
@@ -164,53 +179,154 @@ imagepage =
))) )))
songs = songs =
#(define-void-function (parser location) () #(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.
;; Eingebettete Lieder (embedded_songs.ily) haben jeweils ein eigenes
;; Lesezeichen, daher die Anzahl statt eines Booleans.
(bookmark-count
(lambda (e)
(if (or (eq? (car e) 'emptyPage)
(eq? (car e) 'imagePage)
(eq? (car e) 'markupPage))
0
(let* ((headermodule (ly:book-header (assq-ref (cdr e) 'header)))
(vars (extract-and-check-vars-from-module headermodule '(title starttext))))
(+ (if (or (assq-ref vars 'title) (assq-ref vars 'starttext)) 1 0)
(count song-pdf-bookmark-title (embedded-songs-of-header headermodule)))))))
(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) (+ c (bookmark-count (car l)))))))))
;; 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))))))
;; Aktuell aktives Kapitel (Titel-String) waehrend des Durchlaufs. Wird
;; gesetzt, sobald ein Kapitel aktiviert (aus `pending` entfernt) wird --
;; egal ob auf einer Seite (chapter-prefixed-markup) oder auf dem ersten
;; Song. Jeder danach folgende Song erhaelt dieses Kapitel als
;; chapterref-Header-Feld, woraus toc_include.ily den Kapitel-Index baut.
(current-chapter #f)
;; 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))
(set! current-chapter title)
(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) (for-each (lambda (songitems)
(ly:book-add-bookpart! (ly:parser-lookup '$current-book) (let ((this-index index))
(let ((filename (car songitems)) (set! index (+ index 1))
(songvars (cdr songitems))) (ly:book-add-bookpart! (ly:parser-lookup '$current-book)
(if (eq? filename 'emptyPage) (let ((filename (car songitems))
#{ \bookpart { \markup { \null } } #} (songvars (cdr songitems)))
(if (eq? filename 'imagePage) (if (eq? filename 'emptyPage)
(let ((xsize (assq-ref songvars 'xsize)) #{ \bookpart { \markup { $(chapter-prefixed-markup this-index (make-null-markup)) } } #}
(filename (ly:format "~a/~a" imagePagePath (assq-ref songvars 'filename)))) (if (eq? filename 'markupPage)
#{ \bookpart { ;; Kapitelanfang auf einer markuppage: Kapitel-Eintrag wird dieser
\paper { ;; Seite beigelegt (siehe chapter-prefixed-markup).
%{ #{ \bookpart { \markup { $(chapter-prefixed-markup this-index (assq-ref songvars 'markup)) } } #}
inner-margin = 0 (if (eq? filename 'imagePage)
outer-margin = 0 (let* ((xsize (assq-ref songvars 'xsize))
binding-offset = 0 (filename (ly:format "~a/~a" imagePagePath (assq-ref songvars 'filename)))
top-margin = 0 (img-markup #{ \markup { \pagecenter { \epsfile #X #xsize #filename } } #}))
bottom-margin = 0 #{ \bookpart {
%} \paper {
print-page-number = ##f %{
last-bottom-spacing = #'((basic-distance . 0) (minimum-distance . 0) (padding . 0)) inner-margin = 0
page-count = 1 outer-margin = 0
} binding-offset = 0
\markup { \pagecenter { \epsfile #X #xsize #filename } } top-margin = 0
} #} bottom-margin = 0
) %}
(let* ((newnumber (+ 1 song-number)) print-page-number = ##f
(header #{ \bookpart { $(assq-ref songvars 'header) \header { last-bottom-spacing = #'((basic-distance . 0) (minimum-distance . 0) (padding . 0))
songfilename = $(symbol->string filename) page-count = 1
myindexlabel = #(assq-ref songvars 'label) }
songnumber = #(number->string newnumber) \markup { $(chapter-prefixed-markup this-index img-markup) }
} } #}) } #}
(music (assq-ref songvars 'music)) )
(layout (assq-ref songvars 'layout)) ;; Ist ein Kapitel faellig (Start <= aktuelle Position) und dies ein
(text-pages (assq-ref songvars 'text-pages)) ;; echtes Lied, wird die Kapitelinfo an dieses Lied gehaengt und aus
(label (assq-ref songvars 'label))) ;; `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))
;; Startet das Kapitel erst auf diesem Song (nicht schon auf
;; einer vorangehenden Seite), wird current-chapter jetzt
;; gesetzt und pending entfernt -- vor dem Bau des Headers,
;; damit chapterref bereits das neue Kapitel enthaelt.
(_ (if chaptertitle
(begin (set! current-chapter chaptertitle)
(set! pending (cdr pending)))))
(header #{ \bookpart { $(assq-ref songvars 'header) \header {
songfilename = $(symbol->string filename)
myindexlabel = #(assq-ref songvars 'label)
songnumber = #(number->string newnumber)
chaptertitle = #chaptertitle
chaptercount = #chaptercount
chapterref = #current-chapter
} } #})
(music (assq-ref songvars 'music))
(layout (assq-ref songvars 'layout))
(text-pages (assq-ref songvars 'text-pages))
(label (assq-ref songvars 'label))
(toc-music (header-module-to-toc! (ly:book-header header) label)))
(set! song-number newnumber) (set! song-number newnumber)
;; Eingebettete Lieder: eigene Liednummer, gleiche Seite (label)
(for-each
(lambda (song)
(let ((tocheader (make-module)))
(set! song-number (+ 1 song-number))
(ly:module-copy tocheader song)
(module-define! tocheader 'songnumber (number->string song-number))
(module-define! tocheader 'chapterref current-chapter)
(header-module-to-toc! tocheader label)))
(embedded-songs-of-header (ly:book-header header)))
#{ #{
\bookpart { \bookpart {
$header $header
\headerToTOC #header #label $toc-music
\score { $music \layout { $layout } } \score { $music \layout { $layout songfilename = $(symbol->string filename) } }
$(add-text-pages text-pages) $(add-text-pages text-pages)
} }
#})))))) #}))))))))
(reverse song-list) ordered
)) )))
#(define (boernel-stats) #(define (boernel-stats)
(let ( (let (
+90 -38
View File
@@ -90,7 +90,7 @@
(for-each (lambda (category) (for-each (lambda (category)
(let* ((catsym (string->symbol category)) (let* ((catsym (string->symbol category))
(catlist (hashq-ref category-index-hash catsym (catlist (hashq-ref category-index-hash catsym
(list (list label 'indexCategoryMarkup `(((rawtext . ,category)))))))) (list (list label 'indexCategoryMarkup `(((combine-with-next . #t) (rawtext . ,category))))))))
(if (assq catsym category-names) (if (assq catsym category-names)
(hashq-set! category-index-hash catsym (hashq-set! category-index-hash catsym
(cons (list label markup-symbol textoptions) catlist)) (cons (list label markup-symbol textoptions) catlist))
@@ -114,7 +114,7 @@
(for-each (lambda (authorID) (for-each (lambda (authorID)
(let* ((authorsym (string->symbol authorID)) (let* ((authorsym (string->symbol authorID))
(authorlist (hashq-ref author-index-hash authorsym (authorlist (hashq-ref author-index-hash authorsym
(list (list label 'indexAuthorMarkup `(((rawtext . ,authorID)))))))) (list (list label 'indexAuthorMarkup `(((combine-with-next . #t) (rawtext . ,authorID))))))))
(hashq-set! author-index-hash authorsym (hashq-set! author-index-hash authorsym
(cons (list label markup-symbol textoptions) authorlist)) (cons (list label markup-symbol textoptions) authorlist))
)) ))
@@ -132,6 +132,37 @@
author-index-hash) author-index-hash)
(lambda (a b) (string-ci<? (car a) (car b)))))))) (lambda (a b) (string-ci<? (car a) (car b))))))))
% code for chapter index
% Anders als bei Kategorien/Autoren ergibt sich die Kapitelzugehoerigkeit nicht
% aus dem Song-Header, sondern aus dem \songsChapter, das dem Song vorangeht
% (in book_include.ily als Header-Feld chapterref an jeden Song gehaengt).
% Die Kapitel behalten hier ihre Auftritts-Reihenfolge (nicht alphabetisch),
% ebenso die Songs innerhalb eines Kapitels ihre Song-Reihenfolge.
#(define*-public (add-chapter-index-item! chapter markup-symbol textoptions #:optional label) #f)
#(define-public (chapter-index-items) #f)
#(let ((chapter-index-hash (make-hash-table))
(chapter-order '()))
(set! add-chapter-index-item!
(lambda* (chapter markup-symbol textoptions #:optional (label (gensym "index")))
(let* ((chaptersym (string->symbol chapter))
(existing (hashq-ref chapter-index-hash chaptersym #f))
(chapterlist (or existing
(begin
(set! chapter-order (cons chaptersym chapter-order))
(list (list label 'indexChapterMarkup `(((combine-with-next . #t) (rawtext . ,chapter))))))))
)
(hashq-set! chapter-index-hash chaptersym
(cons (list label markup-symbol textoptions) chapterlist)))
(make-music 'EventChord
'page-marker #t
'page-label label
'elements (list (make-music 'LabelEvent
'page-label label)))))
(set! chapter-index-items (lambda ()
(append-map (lambda (chaptersym) (reverse (hashq-ref chapter-index-hash chaptersym (list))))
(reverse chapter-order)))))
#(define-markup-command (with-link-symbol-ref layout props symbol arg) #(define-markup-command (with-link-symbol-ref layout props symbol arg)
(symbol? markup?) (symbol? markup?)
@@ -215,37 +246,52 @@
(make-null-markup)) (make-null-markup))
\vspace #.4 \vspace #.4
} }
indexChapterMarkup = \markup \override #'(baseline-skip . 1.5) \left-column {
\vspace #1
\sans \bold \fontsize #3 \fromproperty #'index:text
\vspace #.4
}
} }
#(define (prepare-item-markup items layout) #(define (prepare-item-markup items layout)
(map (lambda (index-item) (define (single-item-markup index-item)
(let* ((label (car index-item)) (let* ((label (car index-item))
(index-markup (cadr index-item)) (index-markup (cadr index-item))
(textoptions (caddr index-item)) (textoptions (caddr index-item))
(text (chain-assoc-get 'rawtext textoptions)) (text (chain-assoc-get 'rawtext textoptions))
(alternative (chain-assoc-get 'alternative textoptions)) (alternative (chain-assoc-get 'alternative textoptions))
(songnumber (chain-assoc-get 'songnumber textoptions))) (songnumber (chain-assoc-get 'songnumber textoptions)))
(markup #:override (cons 'index:label label) (markup #:override (cons 'index:label label)
#:override (cons 'index:page (markup #:custom-page-number label -1)) #:override (cons 'index:page (markup #:custom-page-number label -1))
#:override (cons 'index:text text) #:override (cons 'index:text text)
#:override (cons 'index:alternative alternative) #:override (cons 'index:alternative alternative)
#:override (cons 'index:songnumber songnumber) #:override (cons 'index:songnumber songnumber)
(ly:output-def-lookup layout index-markup)))) (ly:output-def-lookup layout index-markup))))
(items))) (if (null? items)
items
(let* ((index-item (car items))
(combine-with-next (chain-assoc-get 'combine-with-next (caddr index-item) #f))
(restitems (cdr items))
(item-markup (single-item-markup index-item)))
(if (and combine-with-next (not (null? restitems)))
(cons (make-column-markup (list item-markup (single-item-markup (car restitems)))) (prepare-item-markup (cdr restitems) layout))
(cons item-markup (prepare-item-markup restitems layout))))
))
#(define-markup-list-command (index-in-columns-with-title layout props index-type title-markup) (symbol? markup?) #(define-markup-list-command (index-in-columns-with-title layout props index-type title-markup) (symbol? markup?)
( _i "Outputs index alphabetical sorted or in categories" ) ( _i "Outputs index alphabetical sorted or in categories" )
(let ((items (case index-type (let ((items (case index-type
((alphabetical) index-items) ((alphabetical) index-items)
((categories) category-index-items) ((categories) category-index-items)
((authors) author-index-items))) ((authors) author-index-items)
((chapters) chapter-index-items)))
(title (interpret-markup layout props title-markup))) (title (interpret-markup layout props title-markup)))
(cons title (cons title
(interpret-markup-list layout props (interpret-markup-list layout props
(make-columnlayout-markup-list songTocColumns 2 (make-columnlayout-markup-list songTocColumns 2
(let ((h (- (ly:output-def-lookup layout 'paper-height) 12))) (let ((h (- (ly:output-def-lookup layout 'paper-height) 12)))
(cons (- h (interval-length (ly:stencil-extent title Y))) h)) (cons (- h (interval-length (ly:stencil-extent title Y))) h))
(prepare-item-markup items layout)))))) (prepare-item-markup (items) layout))))))
indexItem = indexItem =
#(define-music-function (parser location sorttext text) (string? markup?) #(define-music-function (parser location sorttext text) (string? markup?)
@@ -255,36 +301,30 @@ indexItem =
indexSection = indexSection =
#(define-music-function (parser location sorttext text) (string? markup?) #(define-music-function (parser location sorttext text) (string? markup?)
"Add a section line to the alphabetical index, using @code{indexSectionMarkup} paper variable markup. This can be used to divide the alphabetical index into different sections, for example one section for each first letter." "Add a section line to the alphabetical index, using @code{indexSectionMarkup} paper variable markup. This can be used to divide the alphabetical index into different sections, for example one section for each first letter."
(add-index-item! 'indexSectionMarkup (prepend-alist-chain 'rawtext text '()) sorttext)) (add-index-item! 'indexSectionMarkup (prepend-alist-chain 'combine-with-next #t (prepend-alist-chain 'rawtext text '())) sorttext))
#(define (extract-and-check-vars-from-header bookheader varlist) #(define (extract-and-check-vars-from-header bookheader varlist)
(let* ((headervars (hash-map->list cons (struct-ref (ly:book-header bookheader) 0))) (extract-and-check-vars-from-module (ly:book-header bookheader) varlist))
(extract-var-and-check (lambda (headervar)
(let* ((variableref (assoc-ref headervars headervar))
(extracted (if variableref (variable-ref variableref) #f)))
(if (and extracted (not (and (string? extracted) (string-null? extracted)))) extracted #f)))))
(map (lambda (varsymbol)
(cons varsymbol (extract-var-and-check varsymbol))
) varlist)))
headerToTOC = #(define-music-function (parser location header label) (ly:book? symbol?) #(define (header-module-to-toc! headermodule label)
(define (all-author-ids authors) (define (all-author-ids authors)
(let ((poetIds (find-author-ids-by 'text authors)) (let ((poetIds (find-author-ids-by 'text authors))
(translatorIds (find-author-ids-by 'translation authors)) (translatorIds (find-author-ids-by 'translation authors))
(versePoetData (find-author-id-with-part-numbers 'verse authors)) (versePoetData (find-author-id-with-part-numbers 'verse authors))
(composerIds (find-author-ids-by 'melody authors)) (composerIds (find-author-ids-by 'melody authors))
(verseComposerData (find-author-id-with-part-numbers 'meloverse authors)) (verseComposerData (find-author-id-with-part-numbers 'meloverse authors))
(refComposerIds (find-author-ids-by 'meloref authors))
(voiceComposerData (find-author-id-with-part-numbers 'voice authors)) (voiceComposerData (find-author-id-with-part-numbers 'voice authors))
(compositionIds (find-author-ids-by 'composition authors)) (compositionIds (find-author-ids-by 'composition authors))
(adaptionIds (find-author-ids-by 'adaption authors)) (adaptionIds (find-author-ids-by 'adaption authors))
(bridgeIds (find-author-ids-by 'bridge authors)) (bridgeIds (find-author-ids-by 'bridge authors))
(interludeIds (find-author-ids-by 'interlude authors))) (interludeIds (find-author-ids-by 'interlude authors)))
(delete-duplicates (delete-duplicates
(append poetIds translatorIds (map car versePoetData) composerIds (map car verseComposerData) (map car voiceComposerData) compositionIds adaptionIds bridgeIds interludeIds)) (append poetIds translatorIds (map car versePoetData) composerIds (map car verseComposerData) refComposerIds (map car voiceComposerData) compositionIds adaptionIds bridgeIds interludeIds))
)) ))
(let* (let*
( (
(extractedheadervars (extract-and-check-vars-from-header header '(title starttext alttitle categorytitle categories authors songnumber))) (extractedheadervars (extract-and-check-vars-from-module headermodule '(title starttext alttitle categorytitle categories authors songnumber chapterref)))
(title (assq-ref extractedheadervars 'title)) (title (assq-ref extractedheadervars 'title))
(starttext (assq-ref extractedheadervars 'starttext)) (starttext (assq-ref extractedheadervars 'starttext))
(alttitle (assq-ref extractedheadervars 'alttitle)) (alttitle (assq-ref extractedheadervars 'alttitle))
@@ -292,12 +332,14 @@ headerToTOC = #(define-music-function (parser location header label) (ly:book? s
(categories (assq-ref extractedheadervars 'categories)) (categories (assq-ref extractedheadervars 'categories))
(authors (assq-ref extractedheadervars 'authors)) (authors (assq-ref extractedheadervars 'authors))
(songnumber (assq-ref extractedheadervars 'songnumber)) (songnumber (assq-ref extractedheadervars 'songnumber))
(chapterref (assq-ref extractedheadervars 'chapterref))
(textoptions (lambda (text alternative) `(((rawtext . ,text) (alternative . ,alternative) (songnumber . ,songnumber))))) (textoptions (lambda (text alternative) `(((rawtext . ,text) (alternative . ,alternative) (songnumber . ,songnumber)))))
(add-to-toc! (lambda (toctitle alternative) (add-to-toc! (lambda (toctitle alternative)
(add-index-item! 'indexItemMarkup (textoptions toctitle alternative) toctitle label))) (add-index-item! 'indexItemMarkup (textoptions toctitle alternative) toctitle label)))
) )
(if categories (add-category-index-item! (string-tokenize categories) 'indexItemMarkup (textoptions (if categorytitle categorytitle title) #f) label)) (if categories (add-category-index-item! (string-tokenize categories) 'indexItemMarkup (textoptions (if categorytitle categorytitle title) #f) label))
(if authors (add-author-index-item! (all-author-ids authors) 'indexItemMarkup (textoptions (if categorytitle categorytitle title) #f) label)) (if authors (add-author-index-item! (all-author-ids authors) 'indexItemMarkup (textoptions (if categorytitle categorytitle title) #f) label))
(if chapterref (add-chapter-index-item! chapterref 'indexItemMarkup (textoptions (if categorytitle categorytitle title) #f) label))
(if starttext (add-to-toc! starttext #t)) (if starttext (add-to-toc! starttext #t))
(if alttitle (if alttitle
(if (list? alttitle) (if (list? alttitle)
@@ -308,6 +350,9 @@ headerToTOC = #(define-music-function (parser location header label) (ly:book? s
(if title (add-to-toc! title #f) #{ #}) (if title (add-to-toc! title #f) #{ #})
)) ))
headerToTOC = #(define-music-function (parser location header label) (ly:book? symbol?)
(header-module-to-toc! (ly:book-header header) label))
%% https://github.com/NalaGinrut/guile-csv/blob/master/csv/csv.scm %% https://github.com/NalaGinrut/guile-csv/blob/master/csv/csv.scm
@@ -353,11 +398,8 @@ headerToTOC = #(define-music-function (parser location header label) (ly:book? s
(para-lines (map cleanup-whitespaces para-strings))) (para-lines (map cleanup-whitespaces para-strings)))
(string-join para-lines "\n"))) (string-join para-lines "\n")))
(define (generate-toc-csv labelPageTable) (define (generate-toc-csv labelPageTable)
(let ((song-lines (map (lambda (song) (define (song-line filename page-number headermodule)
(let* ((filename (symbol->string (car song))) (let* ((extractedheadervars (extract-and-check-vars-from-module headermodule
(songvars (cdr song))
(page-number (number->string (assoc-get (assq-ref songvars 'label) labelPageTable)))
(extractedheadervars (extract-and-check-vars-from-header (assq-ref songvars 'header)
'(title starttext alttitle categorytitle categories authors year_text year_melody year_translation year_composition year_adaption infotext translation pronunciation copyright source))) '(title starttext alttitle categorytitle categories authors year_text year_melody year_translation year_composition year_adaption infotext translation pronunciation copyright source)))
(headervar-or-empty (lambda (varsym) (headervar-or-empty (lambda (varsym)
(let ((extracted (assq-ref extractedheadervars varsym))) (let ((extracted (assq-ref extractedheadervars varsym)))
@@ -368,6 +410,7 @@ headerToTOC = #(define-music-function (parser location header label) (ly:book? s
(versePoetData (find-author-id-with-part-numbers 'verse authors)) (versePoetData (find-author-id-with-part-numbers 'verse authors))
(composerIds (find-author-ids-by 'melody authors)) (composerIds (find-author-ids-by 'melody authors))
(verseComposerData (find-author-id-with-part-numbers 'meloverse authors)) (verseComposerData (find-author-id-with-part-numbers 'meloverse authors))
(refComposerIds (find-author-ids-by 'meloref authors))
(voiceComposerData (find-author-id-with-part-numbers 'voice authors)) (voiceComposerData (find-author-id-with-part-numbers 'voice authors))
(compositionIds (find-author-ids-by 'composition authors)) (compositionIds (find-author-ids-by 'composition authors))
(adaptionTextIds (find-author-ids-by 'adaption_text authors)) (adaptionTextIds (find-author-ids-by 'adaption_text authors))
@@ -389,7 +432,7 @@ headerToTOC = #(define-music-function (parser location header label) (ly:book? s
(headervar-or-empty 'categories) (headervar-or-empty 'categories)
(format-authors (append poetIds adaptionTextIds (map car versePoetData))) (format-authors (append poetIds adaptionTextIds (map car versePoetData)))
(format-authors translatorIds) (format-authors translatorIds)
(format-authors (append composerIds compositionIds adaptionMusicIds bridgeIds interludeIds (map car voiceComposerData) (map car verseComposerData))) (format-authors (append composerIds compositionIds adaptionMusicIds bridgeIds interludeIds (map car voiceComposerData) (map car verseComposerData) refComposerIds))
(headervar-or-empty 'year_text) (headervar-or-empty 'year_text)
(headervar-or-empty 'year_melody) (headervar-or-empty 'year_melody)
(headervar-or-empty 'year_translation) (headervar-or-empty 'year_translation)
@@ -402,7 +445,16 @@ headerToTOC = #(define-music-function (parser location header label) (ly:book? s
(format-info-paragraphs (headervar-or-empty 'translation)) (format-info-paragraphs (headervar-or-empty 'translation))
(format-info-paragraphs (headervar-or-empty 'pronunciation)) (format-info-paragraphs (headervar-or-empty 'pronunciation))
)))) ))))
(alist-delete 'imagePage (alist-delete 'emptyPage song-list))))) ;; Eingebettete Lieder (embedded_songs.ily) bekommen eigene Zeilen mit
;; Dateiname und Seite des Hauptlieds.
(let ((song-lines (append-map (lambda (song)
(let* ((filename (symbol->string (car song)))
(songvars (cdr song))
(page-number (assoc-get (assq-ref songvars 'label) labelPageTable))
(headermodule (ly:book-header (assq-ref songvars 'header))))
(map (lambda (module) (song-line filename page-number module))
(cons headermodule (embedded-songs-of-header headermodule)))))
(alist-delete 'markupPage (alist-delete 'imagePage (alist-delete 'emptyPage song-list))))))
(call-with-output-file "toc.csv" (call-with-output-file "toc.csv"
(lambda (port) (lambda (port)
(csv-write (cons '( (csv-write (cons '(
@@ -432,6 +484,6 @@ headerToTOC = #(define-music-function (parser location header label) (ly:book? s
; we use a delayed stencil to have all the page references available ; we use a delayed stencil to have all the page references available
(ly:make-stencil (ly:make-stencil
`(delay-stencil-evaluation `(delay-stencil-evaluation
,(delay (let* ((table (ly:output-def-lookup layout 'label-page-table))) ,(delay (let* ((table (ly:output-def-lookup layout 'label-page-string-table)))
(generate-toc-csv (if (list? table) table '())) (generate-toc-csv (if (list? table) table '()))
empty-stencil))))) empty-stencil)))))
+54 -16
View File
@@ -1,8 +1,17 @@
% set the speed of the midi music
#(define midiQuarterNoteSpeed (if (defined? 'midiQuarterNoteSpeed) midiQuarterNoteSpeed 90))
MUSIC = { \transposable #TRANSPOSITION \MUSIC } MUSIC = { \transposable #TRANSPOSITION \MUSIC }
%% Eingebettete Lieder (siehe embedded_songs.ily) im Header des Hauptlieds
%% vermerken, daraus bauen Footer, PDF-Lesezeichen und Verzeichnisse.
#(if (and (pair? EMBEDDED_SONGS) (ly:book? HEADER) (ly:book-header HEADER))
(module-define! (ly:book-header HEADER) 'embeddedsongs EMBEDDED_SONGS))
LAYOUT = \layout {
\LAYOUT
#(customized-layout LAYOUT)
}
#(customize-embedded-score-layouts! (list TEXT TEXT_PAGES))
verselayout = \layout { verselayout = \layout {
\LAYOUT \LAYOUT
\context { \context {
@@ -11,18 +20,12 @@ verselayout = \layout {
} }
} }
LAYOUT = \layout {
\LAYOUT
#(let
((custom-size (ly:output-def-lookup LAYOUT 'size #f)))
(if custom-size (layout-set-staff-size custom-size)))
}
TEXT = \markuplist { TEXT = \markuplist {
\override #`(transposition . ,TRANSPOSITION) \override #`(transposition . ,TRANSPOSITION)
\override #`(verselayout . ,verselayout) \override #`(verselayout . ,verselayout)
\override #`(verse-chords . ,#{ \chords { \verseChords } #}) \override #`(verse-chords . ,#{ \chords { \verseChords } #})
\override #`(verse-reference-voice . ,#{ \global \firstVoice #}) \override #`(verse-reference-voice . ,#{ \global \firstVoice #})
\handle-tag-groups \recordedTagGroups
\TEXT \TEXT
} }
@@ -34,6 +37,7 @@ TEXT = \markuplist {
\override #`(verselayout . ,verselayout) \override #`(verselayout . ,verselayout)
\override #`(verse-chords . ,#{ \chords { \verseChords } #}) \override #`(verse-chords . ,#{ \chords { \verseChords } #})
\override #`(verse-reference-voice . ,#{ \global \firstVoice #}) \override #`(verse-reference-voice . ,#{ \global \firstVoice #})
\handle-tag-groups \recordedTagGroups
#text #text
} }
#}) #})
@@ -44,6 +48,20 @@ TEXT = \markuplist {
TEXT_PAGES TEXT_PAGES
(list TEXT)))) (list TEXT))))
%% Add invisible ChordPro write trigger to last TEXT_PAGES markuplist
#(when (and (defined? 'chordpro-export-enabled) chordpro-export-enabled (pair? TEXT_PAGES))
(let* ((last-index (- (length TEXT_PAGES) 1))
(last-page (list-ref TEXT_PAGES last-index))
(modified-last-page #{
\markuplist {
#last-page
\chordpro-delayed-write
}
#}))
(set! TEXT_PAGES
(append (list-head TEXT_PAGES last-index)
(list modified-last-page)))))
#(define (add-text-pages text-pages) #(define (add-text-pages text-pages)
(if (pair? text-pages) (if (pair? text-pages)
(begin (begin
@@ -60,21 +78,41 @@ TEXT = \markuplist {
(if header (set! $defaultheader header)) (if header (set! $defaultheader header))
(if paper (set! $defaultpaper paper)) (if paper (set! $defaultpaper paper))
) )
;; ChordPro export: Store filename and extract metadata from basicSongInfo FIRST
(when (and (defined? 'chordpro-export-enabled) chordpro-export-enabled)
;; Use ly:parser-output-name which returns the output basename
;; This will write relative to current working directory (same as PDF)
(let ((output-name (ly:parser-output-name)))
(set! chordpro-current-filename output-name))
;; Try to extract metadata from the HEADER (falls back to basicSongInfo)
(let ((header-module (if (and (ly:book? HEADER) (ly:book-header HEADER))
(ly:book-header HEADER)
(and (defined? 'basicSongInfo) basicSongInfo))))
(when header-module
(let* ((header-alist (ly:module->alist header-module))
(title (assoc-ref header-alist 'title))
(authors (assoc-ref header-alist 'authors)))
(when title
(set! chordpro-header-title
(if (markup? title)
(markup->string title)
(if (string? title) title "Untitled"))))
(when authors
(set! chordpro-header-authors authors))))))
(add-score #{ (add-score #{
\score { \score {
\MUSIC \MUSIC
\layout { \LAYOUT } \layout { \LAYOUT }
}#}) }#})
(add-text-pages TEXT_PAGES) (add-text-pages TEXT_PAGES)
(add-score #{ (add-score #{
\score { \score {
\unfoldRepeats { \MUSIC \INLINESCOREMUSIC } \unfoldRepeats { \MUSIC \INLINESCOREMUSIC }
\midi { \midi {
\context {
\Score
% Tempo des midi files
tempoWholesPerMinute = #(/ midiQuarterNoteSpeed 4)
}
\context { \context {
\Staff \Staff
\remove "Staff_performer" \remove "Staff_performer"
@@ -85,4 +123,4 @@ TEXT = \markuplist {
} }
} }
}#}) }#})
)) ))
+1 -1
View File
@@ -4,4 +4,4 @@ HEADER = \bookpart {
\basicSongInfo \basicSongInfo
} }
} }
\include #(if noDefaultOutput "../private_includes/void.ily" "layout_bottom.ily") \include #(if noDefaultOutput "../private_includes/void.ily" "layout_bottom.ily")