diff --git a/private_includes/base/all.ily b/private_includes/base/all.ily index ca6a665..27f28c2 100644 --- a/private_includes/base/all.ily +++ b/private_includes/base/all.ily @@ -33,6 +33,7 @@ #(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 "basic_format_and_style_settings.ily" \include "eps_file_from_song_dir.ily" diff --git a/private_includes/base/basic_format_and_style_settings.ily b/private_includes/base/basic_format_and_style_settings.ily index 45db46a..4256501 100644 --- a/private_includes/base/basic_format_and_style_settings.ily +++ b/private_includes/base/basic_format_and_style_settings.ily @@ -155,50 +155,83 @@ romanStanza = #(define-music-function (parser location) () #{ \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 = -#(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 (handle-stanza-numbers context numbers number-formater) - (let* ((stanzanumbers (ly:assoc-get 'custom-stanzanumber-override (ly:assoc-get 'details (ly:context-grob-definition context 'StanzaNumber) '()) numbers)) - (stanza-style (ly:assoc-get 'style (ly:context-grob-definition context 'StanzaNumber))) - (roman-format (lambda (stanzanumber) (format #f "~@r" stanzanumber)))) - (ly:context-set-property! context 'stanza - (make-pad-left-markup 1 - (number-formater - (if (eq? stanza-style 'roman) - (map roman-format stanzanumbers) - 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 (stanza . stanzanumbers) +#(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-stanza-type = #'verse + \once \override StanzaNumber.details.custom-stanza-type = #type \once \override StanzaNumber.details.custom-stanza-numbers = #stanzanumbers - \applyContext - #(lambda (context) - (handle-stanza-numbers context stanzanumbers - (lambda (numbers) (string-join (map (lambda (n) (format #f stanzaFormat n)) numbers) ", ")))) -#} -) + \stanza \markup \formatted-stanza +#}) + +% \fstanza 1 -> "1." +% \fstanza 1,4 -> "1., 4." (nur im Notenmodus, z.B. \chordverse { \fstanza 1,4 } ...) +% \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 = #(define-music-function (stanzanumbers lyrics) ((number-list? (list)) ly:music?) #{ \lyricmode { - \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-stanza-type = #'ref - \once \override StanzaNumber.details.custom-stanza-numbers = #stanzanumbers - \applyContext - #(lambda (context) - (handle-stanza-numbers context stanzanumbers - (lambda (numbers) - (make-on-the-fly-markup - (lambda (layout props m) - ((ly:output-def-lookup layout 'refMarkupFormatter) layout props numbers)) - (make-null-markup))))) + #(formatted-stanza-music 'ref stanzanumbers) #lyrics } #} @@ -207,43 +240,24 @@ ref = bridge = #(define-music-function (stanzanumbers lyrics) ((number-list? (list)) ly:music?) #{ \lyricmode { - \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-stanza-type = #'bridge - \once \override StanzaNumber.details.custom-stanza-numbers = #stanzanumbers - \applyContext - #(lambda (context) - (handle-stanza-numbers context stanzanumbers - (lambda (numbers) - (make-on-the-fly-markup - (lambda (layout props m) - ((ly:output-def-lookup layout 'bridgeMarkupFormatter) layout props numbers)) - (make-null-markup))))) + #(formatted-stanza-music 'bridge stanzanumbers) #lyrics } #} ) % 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. % Sets custom-inline-text for ChordPro export so it can collect the repeat sign separately -repStartWithTag = \lyricmode { +repStartWithTag = +#(define-music-function () () +#{ \lyricmode { \tag #'repeats { \once \override StanzaNumber.details.custom-inline-text = \repStart \once \override StanzaNumber.details.custom-inline-direction = #LEFT - \applyContext - #(lambda (context) - (let ((lastStanza (ly:context-property context '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 + \stanza \markup \formatted-stanza } -} +} #}) repStopWithTag = \lyricmode { \tag #'repeats { @@ -251,19 +265,19 @@ repStopWithTag = \lyricmode { \once \override StanzaNumber.details.custom-inline-direction = #RIGHT \once \override StanzaNumber.font-series = #'normal \once \override StanzaNumber.direction = 1 - \set stanza = \markup { \pad-x-right #1 \repStop } + \stanza \markup { \pad-x-right #1 \repStop } } } rightHyphen = \lyricmode { \once \override StanzaNumber.font-series = #'normal \once \override StanzaNumber.direction = 1 - \set stanza = "-" + \stanza "-" } leftHyphen = \lyricmode { \once \override StanzaNumber.font-series = #'normal - \set stanza = "-" + \stanza "-" } multiVerseSkips = @@ -329,7 +343,7 @@ rufWithMarkup = \lyricmode { \once \override StanzaNumber.font-series = #'normal \once \override StanzaNumber.direction = 1 - \set stanza = #text + \stanza #text } #}) ruf = diff --git a/private_includes/base/chord_settings.ily b/private_includes/base/chord_settings.ily index 4cd332d..a5fdeef 100644 --- a/private_includes/base/chord_settings.ily +++ b/private_includes/base/chord_settings.ily @@ -155,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 (ly:grob-set-property! grob 'begin-of-line-visible #f)) (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. diff --git a/private_includes/base/chordpro.ily b/private_includes/base/chordpro.ily index 880f570..4f9eecd 100644 --- a/private_includes/base/chordpro.ily +++ b/private_includes/base/chordpro.ily @@ -319,14 +319,21 @@ ;; Use context property if available, otherwise grob property (stanza-markup (or stanza-text-from-context stanza-text-from-grob)) ;; For ref/bridge, always use format-chordpro-stanza-label - ;; For verse, extract from markup (includes roman numerals if \romanStanza was used) - (stanza-text (if (or (eq? stanza-type 'ref) (eq? stanza-type 'bridge)) - (format-chordpro-stanza-label stanza-type stanza-numbers) + ;; For verses set by \fstanza, format the numbers (roman numerals if \romanStanza was used) + ;; Otherwise, extract from markup + (stanza-text (cond + ((or (eq? stanza-type 'ref) (eq? stanza-type 'bridge)) + (format-chordpro-stanza-label stanza-type stanza-numbers)) + (custom-realstanza + (format-stanza-numbers + (ly:assoc-get 'custom-stanzanumber-override details stanza-numbers) + (ly:grob-property grob 'style #f))) + (else (if (markup? stanza-markup) (markup->string stanza-markup) (if stanza-markup (format #f "~a" stanza-markup) - #f)))) + #f))))) (existing (assoc this-verse-index chordpro-stanza-numbers)) (moment (ly:context-current-moment (ly:translator-context source-engraver))) (direction (ly:grob-property grob 'direction CENTER))) diff --git a/private_includes/base/compat_lilypond_2_26.ily b/private_includes/base/compat_lilypond_2_26.ily new file mode 100644 index 0000000..ad1764a --- /dev/null +++ b/private_includes/base/compat_lilypond_2_26.ily @@ -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) diff --git a/private_includes/base/verses_with_chords.ily b/private_includes/base/verses_with_chords.ily index dcde8ba..250d010 100644 --- a/private_includes/base/verses_with_chords.ily +++ b/private_includes/base/verses_with_chords.ily @@ -89,7 +89,7 @@ (if (and (string? arg) (string-null? arg)) " " #{\markup - \score { \new Lyrics { \lyricmode { #(if (ly:music? arg) arg #{ \set stanza = #arg #}) "" } } \layout { $verselayout #(customized-layout verselayout) } } + \score { \new Lyrics { \lyricmode { #(if (ly:music? arg) arg #{ \stanza #arg #}) "" } } \layout { $verselayout #(customized-layout verselayout) } } #} )))