Compare commits
	
		
			27 Commits
		
	
	
		
			chordExcep
			...
			5364f93db4
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 5364f93db4 | |||
| aa0e3816d0 | |||
| 3b0c320839 | |||
| 12abf0a5f7 | |||
| a01e95f31d | |||
| 90feb6dfbb | |||
| ede5568962 | |||
| 66b5c37755 | |||
| cd5e38aabc | |||
| ca129eec79 | |||
| f824b23311 | |||
| 5ef4ee78ae | |||
| 45e751fa24 | |||
| 9fb2d96765 | |||
| 8ce3af93c7 | |||
| 19f6046333 | |||
| a288248da3 | |||
| 7a65d056d6 | |||
| 53c41bf5dc | |||
| c49dba89f7 | |||
| 195110923a | |||
| 8d0ddcee06 | |||
| c47ceb443e | |||
| 377beeab57 | |||
| cb4b74d4f7 | |||
| 616034baca | |||
| 34c9c5a932 | 
| @@ -1,3 +1,9 @@ | |||||||
|  | #(define include_dir_not_added? (if (defined? 'include_dir_not_added?) include_dir_not_added? #t)) | ||||||
|  | #(if include_dir_not_added? | ||||||
|  |    (let* ((common-include-dir (dirname (dirname (dirname (current-filename)))))) | ||||||
|  |       (ly:parser-append-to-include-path common-include-dir) | ||||||
|  |       (set! include_dir_not_added? #f))) | ||||||
|  | 
 | ||||||
| #(define noStandaloneOutput (if (defined? 'noStandaloneOutput) noStandaloneOutput #f)) | #(define noStandaloneOutput (if (defined? 'noStandaloneOutput) noStandaloneOutput #f)) | ||||||
| 
 | 
 | ||||||
| #(define windows? (string-prefix-ci? "windows" (utsname:sysname (uname)))) | #(define windows? (string-prefix-ci? "windows" (utsname:sysname (uname)))) | ||||||
| @@ -13,28 +19,30 @@ | |||||||
|         (string-append (dirname (current-filename)) file-name-separator-string)) |         (string-append (dirname (current-filename)) file-name-separator-string)) | ||||||
|       "scm" file-name-separator-string filename |       "scm" file-name-separator-string filename | ||||||
|     ))))) |     ))))) | ||||||
|     (scm-load "json_parser.scm") |  | ||||||
|     (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 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_DATA (if (defined? 'SONG_DATA) SONG_DATA (parse-yml-file "../../lilypond-song-includes/data/songs.yml"))) | ||||||
| 
 | 
 | ||||||
| \include "basic_format_and_style_settings.ly" | \include "merge_rests_engraver_override.ily" | ||||||
| \include "eps_file_from_song_dir.ly" | \include "basic_format_and_style_settings.ily" | ||||||
| \include "title_with_category_images.ly" | \include "eps_file_from_song_dir.ily" | ||||||
| \include "chord_settings.ly" | \include "title_with_category_images.ily" | ||||||
| \include "transposition.ly" | \include "chord_settings.ily" | ||||||
| \include "verses_with_chords.ly" | \include "transposition.ily" | ||||||
| \include "arrows_in_scores.ly" | \include "verses_with_chords.ily" | ||||||
| \include "swing_style.ly" | \include "arrows_in_scores.ily" | ||||||
| \include "inline_score.ly" | \include "swing_style.ily" | ||||||
|  | \include "inline_score.ily" | ||||||
| \include "custom_indentation.ily" | \include "custom_indentation.ily" | ||||||
|  | \include "include_from_song.ily" | ||||||
| 
 | 
 | ||||||
| % reset important variables | % reset important variables | ||||||
| LAYOUT = \layout { \generalLayout } | LAYOUT = \layout { \generalLayout } | ||||||
| HEADER = {} | HEADER = {} | ||||||
| MUSIC = {} | MUSIC = {} | ||||||
| TEXT = \markuplist {""} | TEXT = \markuplist {} | ||||||
|  | TEXT_PAGES = #f | ||||||
| 
 | 
 | ||||||
| verseChords = {} | verseChords = {} | ||||||
| firstVoice = {} | firstVoice = {} | ||||||
| @@ -1,10 +1,10 @@ | |||||||
| \language "deutsch" | \language "deutsch" | ||||||
| 
 | 
 | ||||||
| \include "default_style.ly" | \include "default_style.ily" | ||||||
| \include "default_songinfo_style.ly" | \include "default_songinfo_style.ily" | ||||||
| \include "footer_with_songinfo.ly" | \include "footer_with_songinfo.ily" | ||||||
| 
 | 
 | ||||||
| \include #(if (defined? 'customStyleOverridesFile) customStyleOverridesFile "void.ly") | \include #(if (defined? 'customStyleOverridesFile) customStyleOverridesFile "../void.ily") | ||||||
| 
 | 
 | ||||||
| #(set-default-paper-size songFormatAndSize) | #(set-default-paper-size songFormatAndSize) | ||||||
| #(set-global-staff-size globalSize) | #(set-global-staff-size globalSize) | ||||||
| @@ -44,7 +44,7 @@ generalLayout = \layout { | |||||||
|   \context { |   \context { | ||||||
|     \Staff |     \Staff | ||||||
|     \accidentalStyle modern-voice-cautionary |     \accidentalStyle modern-voice-cautionary | ||||||
|     \consists Merge_rests_engraver |     \consists \Better_Merge_rests_engraver | ||||||
|   } |   } | ||||||
|   \context { |   \context { | ||||||
|     \Score |     \Score | ||||||
| @@ -67,6 +67,7 @@ generalLayout = \layout { | |||||||
|     % ich will lines breaken wie ich will! |     % ich will lines breaken wie ich will! | ||||||
|     \remove "Forbid_line_break_engraver" |     \remove "Forbid_line_break_engraver" | ||||||
|     \override NoteHead.layer = 2 |     \override NoteHead.layer = 2 | ||||||
|  |     \override Rest.layer = 2 | ||||||
|     \override Dots.layer = 2 |     \override Dots.layer = 2 | ||||||
|     \override Stem.layer = 2 |     \override Stem.layer = 2 | ||||||
|     \override Flag.layer = 2 |     \override Flag.layer = 2 | ||||||
| @@ -83,12 +84,14 @@ textp = \lyricmode { \markup { \raise #1 \musicglyph #"rests.3" } } | |||||||
| % zweite Stimme alles grau | % zweite Stimme alles grau | ||||||
| secondVoiceStyle = { | secondVoiceStyle = { | ||||||
|   \override NoteHead.color = #grey |   \override NoteHead.color = #grey | ||||||
|  |   \override Rest.color = #grey | ||||||
|   \override Dots.color = #grey |   \override Dots.color = #grey | ||||||
|   \override Stem.color = #grey |   \override Stem.color = #grey | ||||||
|   \override Flag.color = #grey |   \override Flag.color = #grey | ||||||
|   \override Beam.color = #grey |   \override Beam.color = #grey | ||||||
|   \override Accidental.color = #grey |   \override Accidental.color = #grey | ||||||
|   \override NoteHead.layer = 1 |   \override NoteHead.layer = 1 | ||||||
|  |   \override Rest.layer = 1 | ||||||
|   \override Dots.layer = 1 |   \override Dots.layer = 1 | ||||||
|   \override Stem.layer = 1 |   \override Stem.layer = 1 | ||||||
|   \override Flag.layer = 1 |   \override Flag.layer = 1 | ||||||
| @@ -98,6 +101,7 @@ secondVoiceStyle = { | |||||||
| 
 | 
 | ||||||
| firstVoiceStyle = { | firstVoiceStyle = { | ||||||
|   \override NoteHead.color = #black |   \override NoteHead.color = #black | ||||||
|  |   \override Rest.color = #black | ||||||
|   \override Dots.color = #black |   \override Dots.color = #black | ||||||
|   \override Stem.color = #black |   \override Stem.color = #black | ||||||
|   \override Flag.color = #black |   \override Flag.color = #black | ||||||
| @@ -121,16 +125,18 @@ override-stanza = | |||||||
| #} | #} | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| stanza = | #(define (stanza . stanzanumbers) | ||||||
| #(define-music-function (parser location stanzanumber) (number?) |  | ||||||
| #{ | #{ | ||||||
|   \once \override StanzaNumber.layer = 23 % set this to signal that there is a real stanza and no repeat signs |   \once \override StanzaNumber.layer = 23 % set this to signal that there is a real stanza and no repeat signs | ||||||
|   \applyContext |   \applyContext | ||||||
|   #(lambda (context) |   #(lambda (context) | ||||||
|     (let* ((stanzanumber (ly:assoc-get 'forced-spacing (ly:context-grob-definition context 'StanzaNumber) stanzanumber)) |     (let* ((stanzanumber-override (ly:assoc-get 'forced-spacing (ly:context-grob-definition context 'StanzaNumber) #f)) | ||||||
|            (stanzastyle (ly:assoc-get 'style (ly:context-grob-definition context 'StanzaNumber))) |            (stanza-style (ly:assoc-get 'style (ly:context-grob-definition context 'StanzaNumber))) | ||||||
|            (formattedStanzaNumber (format #f (if (eq? stanzastyle 'roman) romanStanzaFormat stanzaFormat) stanzanumber))) |            (stanza-format (lambda (stanzanumber) (format #f (if (eq? stanza-style 'roman) romanStanzaFormat stanzaFormat) stanzanumber)))) | ||||||
|         (ly:context-set-property! context 'stanza formattedStanzaNumber))) |         (ly:context-set-property! context 'stanza | ||||||
|  |           (string-join (map stanza-format | ||||||
|  |                             (if stanzanumber-override (list stanzanumber-override) stanzanumbers)) | ||||||
|  |                         ", ")))) | ||||||
| #} | #} | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| @@ -192,12 +198,16 @@ alt = | |||||||
| 
 | 
 | ||||||
| updown = | updown = | ||||||
| #(define-music-function (parser location word) (string?) | #(define-music-function (parser location word) (string?) | ||||||
|  | (let ((first-char (string-take word 1)) | ||||||
|  |       (rest (substring word 1 (string-length word)))) | ||||||
| #{ | #{ | ||||||
|   \lyricmode { |   \lyricmode { | ||||||
|     \tag #'up { \markup { #(string-capitalize word) } } |     \markup { | ||||||
|     \tag #'down { \markup { #(string-downcase word) } } |       \tag #'up #(string-append (string-capitalize first-char) rest) | ||||||
|  |       \tag #'down #(string-append (string-downcase first-char) rest) | ||||||
|     } |     } | ||||||
| #}) |   } | ||||||
|  | #})) | ||||||
| 
 | 
 | ||||||
| dottedExtender = { | dottedExtender = { | ||||||
|   \override LyricExtender.style = #'dotted-line |   \override LyricExtender.style = #'dotted-line | ||||||
| @@ -231,3 +241,19 @@ cue = | |||||||
|             (make-null-markup)) |             (make-null-markup)) | ||||||
|       } |       } | ||||||
|   #}) |   #}) | ||||||
|  | 
 | ||||||
|  | #(define-markup-command (ruf-style layout props text) (string?) | ||||||
|  |    (interpret-markup layout props | ||||||
|  |                      (markup #:italic (string-append "(" text ")")))) | ||||||
|  | rufWithMarkup = | ||||||
|  | #(define-music-function (text) (markup?) | ||||||
|  |    #{ | ||||||
|  |      \lyricmode { | ||||||
|  |        \once \override StanzaNumber.font-series = #'normal | ||||||
|  |        \once \override StanzaNumber.direction = 1 | ||||||
|  |        \set stanza = #text | ||||||
|  |      } | ||||||
|  |    #}) | ||||||
|  | ruf = | ||||||
|  | #(define-music-function (text) (string?) | ||||||
|  |    (rufWithMarkup (make-ruf-style-markup text))) | ||||||
| @@ -68,6 +68,18 @@ altChord = | |||||||
|       #mainchord |       #mainchord | ||||||
|     #})) |     #})) | ||||||
| 
 | 
 | ||||||
|  | % Akkorde werden so transponiert, dass sie passen, wenn man mit Kapo im angegebenen Bund spielt | ||||||
|  | capoTranspose = | ||||||
|  | #(define-music-function (fret chords) (number? ly:music?) | ||||||
|  |   (define semi->pitch | ||||||
|  |     (make-semitone->pitch | ||||||
|  |       (music-pitches | ||||||
|  |         #{ h b a gis g fis f e es d cis c #}))) | ||||||
|  |   (transpose | ||||||
|  |     (ly:pitch-transpose (semi->pitch fret) (ly:make-pitch 0 0)) | ||||||
|  |     (ly:make-pitch 0 0) | ||||||
|  |     chords)) | ||||||
|  | 
 | ||||||
| % kleine Mollakkorde und Alteration ausgeschrieben | % kleine Mollakkorde und Alteration ausgeschrieben | ||||||
| #(define (note-name->german-markup-nosym pitch lowercase?) | #(define (note-name->german-markup-nosym pitch lowercase?) | ||||||
|    (define (pitch-alteration-semitones pitch) (inexact->exact (round (* (ly:pitch-alteration pitch) 2)))) |    (define (pitch-alteration-semitones pitch) (inexact->exact (round (* (ly:pitch-alteration pitch) 2)))) | ||||||
| @@ -2,10 +2,14 @@ | |||||||
|   poetPrefix = "Worte:" |   poetPrefix = "Worte:" | ||||||
|   composerPrefix = "Weise:" |   composerPrefix = "Weise:" | ||||||
|   compositionPrefix = "Satz:" |   compositionPrefix = "Satz:" | ||||||
|  |   adaptionTextPrefix = "Bearbeitung Text:" | ||||||
|  |   adaptionMusicPrefix = "Bearbeitung Musik:" | ||||||
|   poetAndComposerEqualPrefix = "Worte und Weise:" |   poetAndComposerEqualPrefix = "Worte und Weise:" | ||||||
|   voicePrefix = "Stimme:" |   voicePrefix = "Stimme:" | ||||||
|   versePrefix = "Strophe:" |   versePrefix = "Strophe:" | ||||||
|  |   translationAuthorPrefix = "Übersetzung:" | ||||||
|   translationPrefix = "Übersetzung:" |   translationPrefix = "Übersetzung:" | ||||||
|  |   pronunciationPrefix = "Aussprache:" | ||||||
|   interludePrefix = "Zwischenspiel:" |   interludePrefix = "Zwischenspiel:" | ||||||
|   bridgePrefix = "Bridge:" |   bridgePrefix = "Bridge:" | ||||||
| 
 | 
 | ||||||
| @@ -41,8 +45,6 @@ | |||||||
|               (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)) | ||||||
|               (poet-and-composer-oneliner (if (and poet-with-year composer-with-year) (markup poet-with-year between-poet-and-composer-markup composer-with-year) #f)) |  | ||||||
|               (current-line-width (chain-assoc-get 'line-width props (ly:output-def-lookup layout 'line-width))) |  | ||||||
|               (string-with-paragraphs->markuplist (lambda (prefix text) |               (string-with-paragraphs->markuplist (lambda (prefix text) | ||||||
|                 (if text |                 (if text | ||||||
|                   (apply append |                   (apply append | ||||||
| @@ -50,22 +52,26 @@ | |||||||
|                       (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 paragraph) } #})) | ||||||
|                       (ly:regex-split (ly:make-regex "\n[ \t\n]*\n[ \t\n]*") text))) |                       (ly:regex-split (ly:make-regex "\n[ \t\n]*\n[ \t\n]*") (string-append prefix text)))) | ||||||
|                   '())))) |                   '()))) | ||||||
|  |               (poet-and-composer-markup-list | ||||||
|  |                 (string-with-paragraphs->markuplist "" (string-append | ||||||
|  |                   (if poet-with-year (string-append "\n\n" poet-with-year) "") | ||||||
|  |                   (if composer-with-year (string-append "\n\n" composer-with-year) "") | ||||||
|  |                 ))) | ||||||
|  |               (poet-and-composer-oneliner (if (and poet-with-year composer-with-year) (make-line-markup (cons (cadr poet-and-composer-markup-list) (cons between-poet-and-composer-markup (cddr poet-and-composer-markup-list)))) #f)) | ||||||
|  |               (current-line-width (chain-assoc-get 'line-width props (ly:output-def-lookup layout 'line-width)))) | ||||||
|           (stack-lines DOWN 0.0 (chain-assoc-get 'baseline-skip props) |           (stack-lines DOWN 0.0 (chain-assoc-get 'baseline-skip props) | ||||||
|             (interpret-markup-list layout props |             (interpret-markup-list layout props | ||||||
|               (append |               (append | ||||||
|                 (if (and poet-and-composer-oneliner (< (interval-length (ly:stencil-extent (interpret-markup layout props poet-and-composer-oneliner) X)) current-line-width)) |                 (if (and poet-and-composer-oneliner (< (interval-length (ly:stencil-extent (interpret-markup layout props poet-and-composer-oneliner) X)) current-line-width)) | ||||||
|                   (list poet-and-composer-oneliner) |                   (list poet-and-composer-oneliner) | ||||||
|                   (make-wordwrap-string-internal-markup-list #t (string-append |                   poet-and-composer-markup-list) | ||||||
|                     (if poet-with-year (string-append "\n\n" poet-with-year) "") |                 (string-with-paragraphs->markuplist "" (string-append | ||||||
|                     (if composer-with-year (string-append "\n\n" composer-with-year) "") |  | ||||||
|                   ))) |  | ||||||
|                 (make-wordwrap-string-internal-markup-list #t (string-append |  | ||||||
|                   (if copyright (string-append "\n\n© " copyright) ""))) |                   (if copyright (string-append "\n\n© " copyright) ""))) | ||||||
|                 (string-with-paragraphs->markuplist "" infotext) |                 (string-with-paragraphs->markuplist "" infotext) | ||||||
|                 (string-with-paragraphs->markuplist "Übersetzung: " translation) |                 (string-with-paragraphs->markuplist (string-append (ly:output-def-lookup layout 'translationPrefix) " ") translation) | ||||||
|                 (string-with-paragraphs->markuplist "Aussprache: " pronunciation) |                 (string-with-paragraphs->markuplist (string-append (ly:output-def-lookup layout 'pronunciationPrefix) " ") pronunciation) | ||||||
|                   ))))) |                   ))))) | ||||||
|       (make-null-markup) |       (make-null-markup) | ||||||
|     ) |     ) | ||||||
| @@ -4,15 +4,15 @@ | |||||||
|   (interpret-markup-list layout (prepend-alist-chain 'songfilename songfilename props) markuplist)) |   (interpret-markup-list layout (prepend-alist-chain 'songfilename songfilename props) markuplist)) | ||||||
| 
 | 
 | ||||||
| #(define-markup-command (customEps layout props ysize filename)(number? string?) | #(define-markup-command (customEps layout props ysize filename)(number? string?) | ||||||
|    #:properties ((songfilename "") |    #:properties ((songfilename "")) | ||||||
|                  (defaultmarkup #f)) |  | ||||||
|    (interpret-markup layout props |    (interpret-markup layout props | ||||||
|      (let ((filepath (if (string-null? songfilename) |      (let ((defaulttitlemarkup (ly:output-def-lookup layout 'defaultTitleMarkup)) | ||||||
|  |            (filepath (if (string-null? songfilename) | ||||||
|                           filename |                           filename | ||||||
|                           (ly:format "~a/~a/~a" songPath songfilename filename)))) |                           (ly:format "~a/~a/~a" songPath songfilename filename)))) | ||||||
|        (if (file-exists? filepath) |        (if (file-exists? filepath) | ||||||
|              (make-epsfile-markup Y ysize filepath) |              (make-epsfile-markup Y ysize filepath) | ||||||
|              (if defaultmarkup |              (if defaulttitlemarkup | ||||||
|                  defaultmarkup |                  defaulttitlemarkup | ||||||
|                  (ly:format "file does not exist ~a" filepath)) |                  (ly:format "file does not exist ~a" filepath)) | ||||||
| )))) | )))) | ||||||
| @@ -102,14 +102,28 @@ | |||||||
|             (verseComposerData (find-author-id-with-part-numbers 'meloverse authors)) |             (verseComposerData (find-author-id-with-part-numbers 'meloverse 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)) | ||||||
|  |             (adaptionMusicIds (find-author-ids-by 'adaption_music 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)) | ||||||
|             (year_text (chain-assoc-get 'header:year_text props #f)) |             (year_text (chain-assoc-get 'header:year_text props #f)) | ||||||
|             (year_translation (chain-assoc-get 'header:year_translation props #f)) |             (year_translation (chain-assoc-get 'header:year_translation props #f)) | ||||||
|             (year_melody (chain-assoc-get 'header:year_melody props #f)) |             (year_melody (chain-assoc-get 'header:year_melody props #f)) | ||||||
|             (year_composition (chain-assoc-get 'header:year_composition props #f)) |             (year_composition (chain-assoc-get 'header:year_composition props #f)) | ||||||
|  |             (year_adaption_text (chain-assoc-get 'header:year_adaption_text props #f)) | ||||||
|  |             (year_adaption_music (chain-assoc-get 'header:year_adaption_music props #f)) | ||||||
|             ) |             ) | ||||||
|         (if (and (equal? poetIds composerIds) (null? translatorIds) (null? versePoetData) (null? verseComposerData) (null? voiceComposerData) (null? compositionIds) (null? bridgeIds) (null? interludeIds)) |         (if (and | ||||||
|  |               (equal? poetIds composerIds) | ||||||
|  |               (null? translatorIds) | ||||||
|  |               (null? versePoetData) | ||||||
|  |               (null? verseComposerData) | ||||||
|  |               (null? voiceComposerData) | ||||||
|  |               (null? compositionIds) | ||||||
|  |               (null? adaptionTextIds) | ||||||
|  |               (null? adaptionMusicIds) | ||||||
|  |               (null? bridgeIds) | ||||||
|  |               (null? interludeIds)) | ||||||
|           (list |           (list | ||||||
|             (join-present (list |             (join-present (list | ||||||
|               (render-contribution-group (ly:output-def-lookup layout 'poetAndComposerEqualPrefix) poetIds) |               (render-contribution-group (ly:output-def-lookup layout 'poetAndComposerEqualPrefix) poetIds) | ||||||
| @@ -128,12 +142,23 @@ | |||||||
|                   ) ", ") |                   ) ", ") | ||||||
|                   (render-partial-contribution-group 'versePrefix versePoetData) |                   (render-partial-contribution-group 'versePrefix versePoetData) | ||||||
|                   (join-present (list |                   (join-present (list | ||||||
|                     (render-contribution-group (ly:output-def-lookup layout 'translationPrefix) translatorIds) |                     (render-contribution-group (ly:output-def-lookup layout 'translationAuthorPrefix) translatorIds) | ||||||
|                     year_translation |                     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? verseComposerData) (null? voiceComposerData) (null? bridgeIds) (null? interludeIds)) #f |             (if (and | ||||||
|  |                   (null? composerIds) | ||||||
|  |                   (null? compositionIds) | ||||||
|  |                   (null? adaptionMusicIds) | ||||||
|  |                   (null? verseComposerData) | ||||||
|  |                   (null? voiceComposerData) | ||||||
|  |                   (null? bridgeIds) | ||||||
|  |                   (null? interludeIds)) #f | ||||||
|               (string-append |               (string-append | ||||||
|                 (ly:output-def-lookup layout 'composerPrefix) |                 (ly:output-def-lookup layout 'composerPrefix) | ||||||
|                 " " |                 " " | ||||||
| @@ -148,6 +173,10 @@ | |||||||
|                     (render-contribution-group (ly:output-def-lookup layout 'compositionPrefix) compositionIds) |                     (render-contribution-group (ly:output-def-lookup layout 'compositionPrefix) compositionIds) | ||||||
|                     year_composition |                     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 'bridgePrefix) bridgeIds) | ||||||
|                   (render-contribution-group (ly:output-def-lookup layout 'interludePrefix) interludeIds) |                   (render-contribution-group (ly:output-def-lookup layout 'interludePrefix) interludeIds) | ||||||
|                 ) "; ") |                 ) "; ") | ||||||
| @@ -213,13 +242,23 @@ | |||||||
|       `(line-width . ,(* (chain-assoc-get 'header:songinfo-size-factor props songInfoLineWidthFraction) (ly:output-def-lookup layout 'line-width))) |       `(line-width . ,(* (chain-assoc-get 'header:songinfo-size-factor props songInfoLineWidthFraction) (ly:output-def-lookup layout 'line-width))) | ||||||
|       arg))) |       arg))) | ||||||
| 
 | 
 | ||||||
|  | #(define pdf-encode (@@ (lily framework-ps) pdf-encode)) | ||||||
|  | % PDF tags | ||||||
|  | #(define-markup-command (page-number-to-pdf-label layout props) () | ||||||
|  |      (ly:make-stencil | ||||||
|  |       (list 'embedded-ps | ||||||
|  |              (ly:format | ||||||
|  |               "[ /Label (~a) /PAGELABEL pdfmark\n" (pdf-encode (chain-assoc-get 'page:page-number-string props "?")))) | ||||||
|  |       empty-interval empty-interval | ||||||
|  |       )) | ||||||
|  | 
 | ||||||
| \paper { | \paper { | ||||||
|   print-first-page-number = ##t |   print-first-page-number = ##t | ||||||
|   first-page-number = #0 |   first-page-number = #0 | ||||||
| 
 | 
 | ||||||
|   oddFooterMarkup = \markup { |   oddFooterMarkup = \markup { | ||||||
|     \fill-line { |     \fill-line { | ||||||
|       \line { \null } |       \line { \page-number-to-pdf-label \null } | ||||||
|       \line { \if \on-last-page-of-part \general-align #Y #DOWN \fractional-line-width \print-songinfo } |       \line { \if \on-last-page-of-part \general-align #Y #DOWN \fractional-line-width \print-songinfo } | ||||||
|       \line { \if \should-print-page-number \print-pagenumber } |       \line { \if \should-print-page-number \print-pagenumber } | ||||||
|     } |     } | ||||||
| @@ -228,7 +267,7 @@ | |||||||
|     \fill-line { |     \fill-line { | ||||||
|       \line { \if \should-print-page-number \print-pagenumber } |       \line { \if \should-print-page-number \print-pagenumber } | ||||||
|       \line { \if \on-last-page-of-part \general-align #Y #DOWN \fractional-line-width \print-songinfo } |       \line { \if \on-last-page-of-part \general-align #Y #DOWN \fractional-line-width \print-songinfo } | ||||||
|       \line { \null } |       \line { \page-number-to-pdf-label \null } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
							
								
								
									
										15
									
								
								private_includes/base/include_from_song.ily
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								private_includes/base/include_from_song.ily
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | |||||||
|  | includeFromSong = | ||||||
|  | #(define-void-function (filename) (string?) | ||||||
|  |   (let ((noDefaultOutputBackup noDefaultOutput)) | ||||||
|  |     (set! noDefaultOutput #t) | ||||||
|  |     (ly:parser-parse-string (ly:parser-clone) | ||||||
|  |       (ly:format "\\include \"~a\"" | ||||||
|  |       (string-append | ||||||
|  |         (dirname (dirname (dirname (dirname (current-filename))))) | ||||||
|  |         file-name-separator-string | ||||||
|  |         "lilypond-song-includes" | ||||||
|  |         file-name-separator-string | ||||||
|  |         "liedbausteine" | ||||||
|  |         file-name-separator-string | ||||||
|  |         filename))) | ||||||
|  |     (set! noDefaultOutput noDefaultOutputBackup))) | ||||||
							
								
								
									
										86
									
								
								private_includes/base/merge_rests_engraver_override.ily
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								private_includes/base/merge_rests_engraver_override.ily
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,86 @@ | |||||||
|  | Better_Merge_rests_engraver = | ||||||
|  | #(lambda (context) | ||||||
|  |   (define (has-one-or-less? lst) (or (null? lst) (null? (cdr lst)))) | ||||||
|  |   (define (has-at-least-two? lst) (not (has-one-or-less? lst))) | ||||||
|  |   (define (all-equal? lst pred) | ||||||
|  |     (or (has-one-or-less? lst) | ||||||
|  |         (and (pred (car lst) (cadr lst)) (all-equal? (cdr lst) pred)))) | ||||||
|  |   (define (measure-count-eqv? a b) | ||||||
|  |     (eqv? | ||||||
|  |      (ly:grob-property a 'measure-count) | ||||||
|  |      (ly:grob-property b 'measure-count))) | ||||||
|  |  | ||||||
|  |   (define (rests-all-unpitched? rests) | ||||||
|  |     "Returns true when all rests do not override the staff-position grob | ||||||
|  |     property. When a rest has a position set we do not want to merge rests at | ||||||
|  |     that position." | ||||||
|  |     (every (lambda (rest) (null? (ly:grob-property rest 'staff-position))) rests)) | ||||||
|  |  | ||||||
|  |   (define (less-by-layer a b) | ||||||
|  |     (< | ||||||
|  |       (ly:grob-property b 'layer 0) | ||||||
|  |       (ly:grob-property a 'layer 0))) | ||||||
|  |  | ||||||
|  |   (define (merge-mmrests mmrests) | ||||||
|  |     "Move all multimeasure rests to the single voice location." | ||||||
|  |     (if (all-equal? mmrests measure-count-eqv?) | ||||||
|  |         (begin | ||||||
|  |           (for-each | ||||||
|  |            (lambda (rest) (ly:grob-set-property! rest 'direction CENTER)) | ||||||
|  |            mmrests) | ||||||
|  |           (for-each | ||||||
|  |            (lambda (rest) (ly:grob-set-property! rest 'transparent #t)) | ||||||
|  |            (cdr (sort mmrests less-by-layer)))))) | ||||||
|  |  | ||||||
|  |   (define (merge-rests rests) | ||||||
|  |     (for-each | ||||||
|  |      (lambda (rest) (ly:grob-set-property! rest 'staff-position 0)) | ||||||
|  |      rests) | ||||||
|  |     (for-each | ||||||
|  |      (lambda (rest) (ly:grob-set-property! rest 'transparent #t)) | ||||||
|  |      (cdr (sort rests less-by-layer)))) | ||||||
|  |  | ||||||
|  |   (let ((mmrests '()) | ||||||
|  |         (rests '()) | ||||||
|  |         (dots '())) | ||||||
|  |     (make-engraver | ||||||
|  |      ((start-translation-timestep translator) | ||||||
|  |       (set! rests '()) | ||||||
|  |       (set! mmrests '()) | ||||||
|  |       (set! dots '())) | ||||||
|  |      (acknowledgers | ||||||
|  |       ((dot-column-interface engraver grob source-engraver) | ||||||
|  |        (if (not (ly:context-property context 'suspendRestMerging #f)) | ||||||
|  |            (set! | ||||||
|  |             dots | ||||||
|  |             (append (ly:grob-array->list (ly:grob-object grob 'dots)) | ||||||
|  |                     dots)))) | ||||||
|  |       ((rest-interface engraver grob source-engraver) | ||||||
|  |        (cond | ||||||
|  |         ((ly:context-property context 'suspendRestMerging #f) | ||||||
|  |          #f) | ||||||
|  |         ((grob::has-interface grob 'multi-measure-rest-interface) | ||||||
|  |          (set! mmrests (cons grob mmrests))) | ||||||
|  |         (else | ||||||
|  |          (set! rests (cons grob rests)))))) | ||||||
|  |      ((stop-translation-timestep translator) | ||||||
|  |       (let (;; get a list of the rests 'duration-lengths, 'duration-log does | ||||||
|  |             ;; not take dots into account | ||||||
|  |             (durs | ||||||
|  |              (map | ||||||
|  |               (lambda (g) | ||||||
|  |                 (ly:duration->moment | ||||||
|  |                  (ly:prob-property | ||||||
|  |                   (ly:grob-property g 'cause) | ||||||
|  |                   'duration))) | ||||||
|  |               rests))) | ||||||
|  |         (if (and | ||||||
|  |              (has-at-least-two? rests) | ||||||
|  |              (all-equal? durs equal?) | ||||||
|  |              (rests-all-unpitched? rests)) | ||||||
|  |             (begin | ||||||
|  |               (merge-rests rests) | ||||||
|  |               ;; ly:grob-suicide! works nicely for dots, as opposed to rests. | ||||||
|  |               (if (pair? dots) (for-each ly:grob-suicide! (cdr dots))))) | ||||||
|  |         (if (has-at-least-two? mmrests) | ||||||
|  |             (merge-mmrests mmrests))))))) | ||||||
							
								
								
									
										154
									
								
								private_includes/base/scm/yaml_parser.scm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								private_includes/base/scm/yaml_parser.scm
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,154 @@ | |||||||
|  | (use-modules (ice-9 rdelim) (ice-9 regex) (ice-9 pretty-print) (srfi srfi-1)) | ||||||
|  |  | ||||||
|  | ;; Hauptparsingfunktion | ||||||
|  | (define (yml-file->scm filename) | ||||||
|  |  | ||||||
|  |   ;; Utility: Zeile einlesen | ||||||
|  |   (define (read-lines filename) | ||||||
|  |     (call-with-input-file filename | ||||||
|  |       (lambda (port) | ||||||
|  |         (let loop ((lines '())) | ||||||
|  |           (let ((line (read-line port))) | ||||||
|  |             (if (eof-object? line) | ||||||
|  |                 (reverse lines) | ||||||
|  |                 (let ((clean (string-trim line))) | ||||||
|  |                   (if (or (string=? clean "---") (string-null? clean)) | ||||||
|  |                       (loop lines) ;; Ignoriere "---" oder leere Zeile | ||||||
|  |                       (loop (cons line lines)))))))))) | ||||||
|  |  | ||||||
|  |   ;; Einrückung bestimmen (Anzahl Leerzeichen am Anfang) | ||||||
|  |   (define (line-indent line) | ||||||
|  |     (let ((match (string-match "^ *" line))) | ||||||
|  |       (if match | ||||||
|  |           (match:end match)  ; Anzahl der Leerzeichen = Position nach Leerzeichen | ||||||
|  |           0)))               ; Falls kein Match → 0 | ||||||
|  |  | ||||||
|  |   ;; Kommentar entfernen | ||||||
|  |   (define (strip-comment line) | ||||||
|  |     (let ((m (string-match "#.*" line))) | ||||||
|  |       (if m | ||||||
|  |           (string-trim-right (string-take line (match:start m))) | ||||||
|  |           line))) | ||||||
|  |  | ||||||
|  |   ;; Hilfsfunktion: Whitespace entfernen | ||||||
|  |   (define (clean-line line) | ||||||
|  |     (string-trim (strip-comment line))) | ||||||
|  |  | ||||||
|  |   ;; Ist Zeile leer (nach Entfernen von Kommentar & Whitespace)? | ||||||
|  |   (define (blank-or-comment? line) | ||||||
|  |     (string-null? (clean-line line))) | ||||||
|  |  | ||||||
|  |   ;; Skalare Werte interpretieren | ||||||
|  |   (define (parse-scalar str) | ||||||
|  |     (define (strip-quotes s) | ||||||
|  |       (cond | ||||||
|  |        ((and (string-prefix? "\"" s) (string-suffix? "\"" s)) | ||||||
|  |         (string-drop-right (string-drop s 1) 1)) | ||||||
|  |        ((and (string-prefix? "'" s) (string-suffix? "'" s)) | ||||||
|  |         (string-drop-right (string-drop s 1) 1)) | ||||||
|  |        (else s))) | ||||||
|  |     (let ((s (strip-quotes (string-trim str)))) | ||||||
|  |       (cond | ||||||
|  |        ((string=? s "{}") '())  ;; leere Map | ||||||
|  |        ((string=? s "[]") '())  ;; leere Liste | ||||||
|  |        ((string-match "^[0-9]+$" s) (string->number s)) | ||||||
|  |        ((string=? s "true") #t) | ||||||
|  |        ((string=? s "false") #f) | ||||||
|  |        ((string=? s "null") '()) | ||||||
|  |        (else s)))) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   ;; Hilfsfunktion: Zeilen mit gleicher oder höherer Einrückung sammeln | ||||||
|  |   (define (take-indented lines min-indent) | ||||||
|  |     (let loop ((ls lines) (acc '())) | ||||||
|  |       (if (null? ls) | ||||||
|  |           (reverse acc) | ||||||
|  |           (let ((line (car ls))) | ||||||
|  |             (if (or (blank-or-comment? line) | ||||||
|  |                     (>= (line-indent line) min-indent)) | ||||||
|  |                 (loop (cdr ls) (cons line acc)) | ||||||
|  |                 (reverse acc)))))) | ||||||
|  |  | ||||||
|  |   ;; Hilfsfunktion: N Zeilen überspringen | ||||||
|  |   (define (drop lst n) | ||||||
|  |     (let loop ((l lst) (i n)) | ||||||
|  |       (if (or (zero? i) (null? l)) | ||||||
|  |           l | ||||||
|  |           (loop (cdr l) (- i 1))))) | ||||||
|  |  | ||||||
|  |   ;; Listenparsing: Liest Zeilen mit `-` als Listeneinträge | ||||||
|  |   (define (parse-list lines current-indent) | ||||||
|  |     (let loop ((ls lines) (result '())) | ||||||
|  |       (if (null? ls) | ||||||
|  |           (reverse result) | ||||||
|  |           (let* ((line (clean-line (car ls)))) | ||||||
|  |             (if (string-match "^-" line) | ||||||
|  |                 (let* ((indent (line-indent (car ls))) | ||||||
|  |                        (item-str (string-trim (string-drop line 1))) | ||||||
|  |                        (next-lines (cdr ls))) | ||||||
|  |                   (if (or (null? next-lines) | ||||||
|  |                           (> (line-indent (car next-lines)) indent)) | ||||||
|  |                       ;; Verschachtelter Inhalt | ||||||
|  |                       (let* ((sub (take-indented next-lines (+ indent 2))) | ||||||
|  |                              (parsed (if (null? sub) | ||||||
|  |                                          (parse-scalar item-str) | ||||||
|  |                                          (parse-lines sub (+ indent 2)))) | ||||||
|  |                              (remaining (drop next-lines (length sub)))) | ||||||
|  |                         (loop remaining (cons parsed result))) | ||||||
|  |                       ;; Einfacher Skalar | ||||||
|  |                       (loop next-lines (cons (parse-scalar item-str) result)))) | ||||||
|  |                 ;; Nicht mehr Teil der Liste | ||||||
|  |                 (reverse result)))))) | ||||||
|  |  | ||||||
|  |   ;; Hauptparser für Key-Value oder Listen | ||||||
|  |   (define (parse-lines lines current-indent) | ||||||
|  |     (let loop ((ls lines) (result '())) | ||||||
|  |       (if (null? ls) | ||||||
|  |           (reverse result) | ||||||
|  |           (let* ((raw-line (car ls)) | ||||||
|  |                  (line (clean-line raw-line))) | ||||||
|  |             (cond | ||||||
|  |              ;; Kommentar oder leere Zeile | ||||||
|  |              ((blank-or-comment? raw-line) | ||||||
|  |               (loop (cdr ls) result)) | ||||||
|  |  | ||||||
|  |              ;; Liste | ||||||
|  |              ((string-match "^- " line) | ||||||
|  |               (let ((list-lines (take-indented ls current-indent))) | ||||||
|  |                 (let ((parsed-list (parse-list list-lines current-indent))) | ||||||
|  |                   (loop (drop ls (length list-lines)) | ||||||
|  |                         (cons parsed-list result))))) | ||||||
|  |  | ||||||
|  |              ;; Key: Value | ||||||
|  |              ((string-match "^[^:]+:" line) | ||||||
|  |               (let* ((kv (string-split line #\:)) | ||||||
|  |                      (key (string-trim (car kv))) | ||||||
|  |                      (value-str (string-trim (string-join (cdr kv) ":"))) | ||||||
|  |                      (next-lines (cdr ls))) | ||||||
|  |                 (if (string-null? value-str) | ||||||
|  |                     ;; Wert auf nachfolgender Einrückungsebene | ||||||
|  |                     (let* ((sub (take-indented next-lines (+ current-indent 2))) | ||||||
|  |                            (parsed (parse-lines sub (+ current-indent 2))) | ||||||
|  |                            (remaining (drop next-lines (length sub)))) | ||||||
|  |                       (loop remaining | ||||||
|  |                             (cons (cons key parsed) result))) | ||||||
|  |                     ;; Einfacher Key:Value | ||||||
|  |                     (loop next-lines | ||||||
|  |                           (cons (cons key (parse-scalar value-str)) result))))) | ||||||
|  |  | ||||||
|  |              ;; Fehlerhafte Zeile | ||||||
|  |              (else | ||||||
|  |                ;; Vermeide Fehlermeldung für Leerzeilen oder leere Objekte | ||||||
|  |                (if (or (string-null? (string-trim line)) | ||||||
|  |                        (member line '("{}" "[]"))) | ||||||
|  |                    (loop (cdr ls) result) | ||||||
|  |                    (begin | ||||||
|  |                      (format (current-error-port) | ||||||
|  |                              "Syntaxfehler: Ungültige Zeile: ~a\n" raw-line) | ||||||
|  |                      (loop (cdr ls) result)))) | ||||||
|  |              ))))) | ||||||
|  |  | ||||||
|  |   (let ((lines (read-lines filename))) | ||||||
|  |     (parse-lines lines 0))) | ||||||
|  |  | ||||||
|  | (define (parse-yml-file filename) (resolve-inherits (yml-file->scm filename))) | ||||||
| @@ -1,16 +1,6 @@ | |||||||
| #(define-markup-command (bookTitleMarkupCustom layout props)() | #(define-markup-command (bookTitleMarkupCustom layout props)() | ||||||
|    (interpret-markup layout |    (interpret-markup layout | ||||||
|      (prepend-alist-chain 'defaultmarkup #{ |      (prepend-alist-chain 'songfilename (chain-assoc-get 'header:songfilename props "") props) | ||||||
| \markup { |  | ||||||
|   \override #'(baseline-skip . 3.5) |  | ||||||
|   \center-column { |  | ||||||
|     \override #`(font-name . ,songTitleFont) { \fontsize #songTitleSize \fromproperty #'header:title } |  | ||||||
|     \large \bold \fromproperty #'header:subtitle |  | ||||||
|     \smaller \bold \fromproperty #'header:subsubtitle |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|                            #} |  | ||||||
|      (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)) | ||||||
| @@ -38,13 +28,15 @@ | |||||||
| #(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?) | #(define-markup-command (title-to-pdf-toc layout props title) (string?) | ||||||
|  |   (if (string-null? title) | ||||||
|  |      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))) |               "[/Action /GoTo /View [/XYZ -4 currentpagedevice /PageSize get 1 get 4 add null] /Title (~a) /OUT pdfmark" (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?) | #(define-markup-command (title-with-category-images layout props right)(boolean?) | ||||||
|    (interpret-markup layout props |    (interpret-markup layout props | ||||||
| @@ -63,4 +55,12 @@ | |||||||
|   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 \title-with-category-images ##t } | ||||||
|   evenHeaderMarkup = \markup { \if \on-first-page-of-part \title-with-category-images ##f } |   evenHeaderMarkup = \markup { \if \on-first-page-of-part \title-with-category-images ##f } | ||||||
|  |   defaultTitleMarkup = \markup { | ||||||
|  |     \override #'(baseline-skip . 3.5) | ||||||
|  |     \center-column { | ||||||
|  |       \override #`(font-name . ,songTitleFont) { \fontsize #songTitleSize \fromproperty #'header:title } | ||||||
|  |       \large \bold \fromproperty #'header:subtitle | ||||||
|  |       \smaller \bold \fromproperty #'header:subsubtitle | ||||||
|  |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
| @@ -221,14 +221,28 @@ | |||||||
|                        (cons (car x) (+ (cdr x) amount)) |                        (cons (car x) (+ (cdr x) amount)) | ||||||
|                        y))) |                        y))) | ||||||
| 
 | 
 | ||||||
| #(define-markup-command (score-equal-height layout props reference-height lines) | #(define-markup-command (score-equal-height-with-indents layout props lines) | ||||||
|   (number? markup-list?) |   (markup-list?) | ||||||
|   #:category music |   #:category music | ||||||
|   #:properties ((baseline-skip)) |   #:properties ((intraverse-vspace 0) | ||||||
|     (stack-stencils Y DOWN baseline-skip |                 (verse-line-height songTextLineHeigth) | ||||||
|       (map |                 (line-indents '())) | ||||||
|         (lambda (line) (ly:make-stencil (ly:stencil-expr line) (ly:stencil-extent line X) `(,(/ reference-height -2.0) . ,(/ reference-height 2.0)))) |     (let ((indents-max-index (- (length line-indents) 1))) | ||||||
|         (interpret-markup-list layout props lines)))) |       (stack-stencils Y DOWN intraverse-vspace | ||||||
|  |         (index-map | ||||||
|  |           (lambda (index line) | ||||||
|  |             (let ((stil | ||||||
|  |                     (ly:make-stencil | ||||||
|  |                       (ly:stencil-expr line) | ||||||
|  |                       (ly:stencil-extent line X) | ||||||
|  |                       `(,(/ verse-line-height -2.0) . ,(/ verse-line-height 2.0))))) | ||||||
|  |               (if (<= index indents-max-index) | ||||||
|  |                 (ly:stencil-translate-axis | ||||||
|  |                   stil | ||||||
|  |                   (list-ref line-indents index) | ||||||
|  |                   X) | ||||||
|  |                 stil))) | ||||||
|  |           (interpret-markup-list layout props lines))))) | ||||||
| 
 | 
 | ||||||
| #(define-public (custom-lyric-text::print grob) | #(define-public (custom-lyric-text::print grob) | ||||||
|   "Allow interpretation of tildes as lyric tieing marks." |   "Allow interpretation of tildes as lyric tieing marks." | ||||||
| @@ -243,20 +257,17 @@ | |||||||
|    #:properties ((verse-chords #{#}) |    #:properties ((verse-chords #{#}) | ||||||
|                  (verse-reference-voice #{#}) |                  (verse-reference-voice #{#}) | ||||||
|                  (verse-break-voice #{#}) |                  (verse-break-voice #{#}) | ||||||
|                  (verse-line-height songTextLineHeigth) |  | ||||||
|                  (verse-text-chord-distance songTextChordDistance) |                  (verse-text-chord-distance songTextChordDistance) | ||||||
|                  (intraverse-vspace 0) |  | ||||||
|                  (transposition (cons #f #f)) |                  (transposition (cons #f #f)) | ||||||
|                  (verselayout generalLayout)) |                  (verselayout generalLayout)) | ||||||
|   "Vers mit Akkorden" |   "Vers mit Akkorden" | ||||||
|   (interpret-markup layout props |   (interpret-markup layout props | ||||||
|     #{ |     #{ | ||||||
|       \markup { |       \markup { | ||||||
|         \override #`(baseline-skip . ,intraverse-vspace) |         \score-equal-height-with-indents \score-lines { | ||||||
|         \score-equal-height #verse-line-height \score-lines { |  | ||||||
|           << |           << | ||||||
|             \new Devnull { #verse-break-voice } |             \new Devnull { #(music-clone verse-break-voice) } | ||||||
|             \new NullVoice = "dummyvoice" { #verse-reference-voice } |             \new NullVoice = "dummyvoice" { #(music-clone verse-reference-voice) } | ||||||
|             \transposable #transposition #(music-clone verse-chords) |             \transposable #transposition #(music-clone verse-chords) | ||||||
|             \new Lyrics \lyricsto "dummyvoice" { #lyrics } |             \new Lyrics \lyricsto "dummyvoice" { #lyrics } | ||||||
|           >> |           >> | ||||||
| @@ -269,6 +280,7 @@ | |||||||
|             \context { |             \context { | ||||||
|               \Lyrics |               \Lyrics | ||||||
|               \override VerticalAxisGroup.nonstaff-relatedstaff-spacing.basic-distance = #verse-text-chord-distance |               \override VerticalAxisGroup.nonstaff-relatedstaff-spacing.basic-distance = #verse-text-chord-distance | ||||||
|  |               \override VerticalAxisGroup.nonstaff-relatedstaff-spacing.padding = #(- verse-text-chord-distance songTextChordDistance) | ||||||
|               \override LyricText.parent-alignment-X = #LEFT |               \override LyricText.parent-alignment-X = #LEFT | ||||||
|               \override LyricText.self-alignment-X = #LEFT |               \override LyricText.self-alignment-X = #LEFT | ||||||
|               \override LyricText.word-space = 0.8 |               \override LyricText.word-space = 0.8 | ||||||
| @@ -292,6 +304,7 @@ | |||||||
|               \remove Jump_engraver |               \remove Jump_engraver | ||||||
|               \remove Volta_engraver |               \remove Volta_engraver | ||||||
|               \remove Parenthesis_engraver |               \remove Parenthesis_engraver | ||||||
|  |               \remove Metronome_mark_engraver | ||||||
|             } |             } | ||||||
|             \context { |             \context { | ||||||
|               \Staff |               \Staff | ||||||
| @@ -313,13 +326,15 @@ | |||||||
|               \remove Tie_engraver |               \remove Tie_engraver | ||||||
|               \remove Dynamic_engraver |               \remove Dynamic_engraver | ||||||
|               \remove Note_heads_engraver |               \remove Note_heads_engraver | ||||||
|  |               \remove Script_engraver | ||||||
|             } |             } | ||||||
|             \context { |             \context { | ||||||
|               \NullVoice |               \NullVoice | ||||||
|               \consists Rest_engraver |               \consists Rest_engraver | ||||||
|               \omit Rest |               \omit Rest | ||||||
|              % \undo \omit NoteHead |               \undo \omit NoteHead | ||||||
|              % \hide NoteHead |               \hide NoteHead | ||||||
|  |               \override NoteHead.X-extent = #'(0 . 0) | ||||||
|             } |             } | ||||||
|           } |           } | ||||||
|         } |         } | ||||||
| @@ -1,4 +1,5 @@ | |||||||
| #(define song-list '()) | #(define song-list '()) | ||||||
|  | #(define song-number 0) | ||||||
| 
 | 
 | ||||||
| #(define (files-in-directory dirname) | #(define (files-in-directory dirname) | ||||||
|       ;;; Generate list containing filenames |       ;;; Generate list containing filenames | ||||||
| @@ -64,7 +65,10 @@ additionalPageNumbers = | |||||||
|   display-pages-list |   display-pages-list | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| 
 | % TODO: | ||||||
|  | % Eigentlich können wir das direkt in oddFooderMarkup und evenFooterMarkup aufrufen | ||||||
|  | % vermutlich sogar ohne den delay kram. Wir sollten außerdem einfach nur die property | ||||||
|  | % page:page-number-string setzen dann klappts auch mit PDF Seiten | ||||||
| #(define-markup-command (custom-page-number layout props label real-current-page-number) | #(define-markup-command (custom-page-number layout props label real-current-page-number) | ||||||
|   (symbol? number?) |   (symbol? number?) | ||||||
|   #:category other |   #:category other | ||||||
| @@ -88,9 +92,10 @@ width may require additional tweaking.)" | |||||||
|         ,(delay (ly:stencil-expr |         ,(delay (ly:stencil-expr | ||||||
|                  (let* ((display-page (assq-ref (build-display-pages-list layout) label)) |                  (let* ((display-page (assq-ref (build-display-pages-list layout) label)) | ||||||
|                         (real-current-page (if (negative? real-current-page-number) (real-page-number layout label) real-current-page-number)) |                         (real-current-page (if (negative? real-current-page-number) (real-page-number layout label) real-current-page-number)) | ||||||
|  |                         (number-type (ly:output-def-lookup layout 'page-number-type)) | ||||||
|                         (page-markup |                         (page-markup | ||||||
|                           (if (assq-ref additional-page-switch-label-list label) |                           (if (assq-ref additional-page-switch-label-list label) | ||||||
|                               (make-concat-markup (list (number-format 'arabic display-page) |                               (make-concat-markup (list (number-format number-type display-page) | ||||||
|                                 (make-char-markup (+ 97 (- real-current-page (real-page-number layout |                                 (make-char-markup (+ 97 (- real-current-page (real-page-number layout | ||||||
|                                   (let find-earliest-additional-label |                                   (let find-earliest-additional-label | ||||||
|                                        ((rest-additional-page-switch-label-list (member (cons label #t) additional-page-switch-label-list))) |                                        ((rest-additional-page-switch-label-list (member (cons label #t) additional-page-switch-label-list))) | ||||||
| @@ -98,7 +103,7 @@ width may require additional tweaking.)" | |||||||
|                                            (find-earliest-additional-label (cdr rest-additional-page-switch-label-list)) |                                            (find-earliest-additional-label (cdr rest-additional-page-switch-label-list)) | ||||||
|                                            (caar rest-additional-page-switch-label-list))) |                                            (caar rest-additional-page-switch-label-list))) | ||||||
|                                 )))))) |                                 )))))) | ||||||
|                               (number-format 'arabic (+ display-page (- real-current-page (real-page-number layout label)))) |                               (number-format number-type (+ display-page (- real-current-page (real-page-number layout label)))) | ||||||
|                           )) |                           )) | ||||||
|                         (page-stencil (interpret-markup layout props page-markup)) |                         (page-stencil (interpret-markup layout props page-markup)) | ||||||
|                         (gap (- (interval-length x-ext) |                         (gap (- (interval-length x-ext) | ||||||
| @@ -114,7 +119,7 @@ width may require additional tweaking.)" | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| includeSong = | includeSong = | ||||||
| #(define-void-function (parser location textproc filename) ((procedure?) string?) | #(define-void-function (parser location filename) (string?) | ||||||
|      #{ |      #{ | ||||||
|      \bookOutputName #filename |      \bookOutputName #filename | ||||||
|      #} |      #} | ||||||
| @@ -125,7 +130,15 @@ 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 (acons 'music MUSIC (acons 'layout LAYOUT (acons 'text #{ \markuplist \setsongfilename $filename $(if textproc (textproc TEXT) TEXT) #} '()))))) |           (acons 'label label | ||||||
|  |             (acons 'header HEADER | ||||||
|  |               (acons 'music MUSIC | ||||||
|  |                 (acons 'layout LAYOUT | ||||||
|  |                   (acons 'text-pages | ||||||
|  |                     (map (lambda (text) | ||||||
|  |                       #{ \markuplist \setsongfilename $filename $text #}) | ||||||
|  |                       TEXT_PAGES) | ||||||
|  |                     '()))))) | ||||||
|           song-list)) |           song-list)) | ||||||
|     )) |     )) | ||||||
| 
 | 
 | ||||||
| @@ -177,21 +190,23 @@ songs = | |||||||
|               \markup { \pagecenter { \epsfile #X #xsize #filename } } |               \markup { \pagecenter { \epsfile #X #xsize #filename } } | ||||||
|           } #} |           } #} | ||||||
|           ) |           ) | ||||||
|           (let ((header #{ \bookpart { $(assq-ref songvars 'header) \header { |           (let* ((newnumber (+ 1 song-number)) | ||||||
|  |                  (header #{ \bookpart { $(assq-ref songvars 'header) \header { | ||||||
|                    songfilename = $(symbol->string filename) |                    songfilename = $(symbol->string filename) | ||||||
|                    myindexlabel = #(assq-ref songvars 'label) |                    myindexlabel = #(assq-ref songvars 'label) | ||||||
|  |                    songnumber = #(number->string newnumber) | ||||||
|                  } } #}) |                  } } #}) | ||||||
|                 ;(header (assq-ref songvars 'header)) |  | ||||||
|                  (music (assq-ref songvars 'music)) |                  (music (assq-ref songvars 'music)) | ||||||
|                  (layout (assq-ref songvars 'layout)) |                  (layout (assq-ref songvars 'layout)) | ||||||
|                 (text (assq-ref songvars 'text)) |                  (text-pages (assq-ref songvars 'text-pages)) | ||||||
|                  (label (assq-ref songvars 'label))) |                  (label (assq-ref songvars 'label))) | ||||||
|  |             (set! song-number newnumber) | ||||||
|             #{ |             #{ | ||||||
|               \bookpart { |               \bookpart { | ||||||
|                 $header |                 $header | ||||||
|                 \headerToTOC #header #label |                 \headerToTOC #header #label | ||||||
|                 \score { $music \layout { $layout } } |                 \score { $music \layout { $layout } } | ||||||
|                 $text |                 $(add-text-pages text-pages) | ||||||
|               } |               } | ||||||
|             #})))))) |             #})))))) | ||||||
|    (reverse song-list) |    (reverse song-list) | ||||||
| @@ -56,24 +56,25 @@ | |||||||
| 
 | 
 | ||||||
| #(let ((index-item-list (list))) | #(let ((index-item-list (list))) | ||||||
|    (set! add-index-item! |    (set! add-index-item! | ||||||
|    (lambda* (markup-symbol text sorttext #:optional (label (gensym "index"))) |    (lambda* (markup-symbol textoptions sorttext #:optional (label (gensym "index"))) | ||||||
|        (set! index-item-list |        (set! index-item-list | ||||||
|        ;; We insert index items sorted from the beginning on and do |        ;; We insert index items sorted from the beginning on and do | ||||||
|        ;; not sort them later - this saves pretty much computing time |        ;; not sort them later - this saves pretty much computing time | ||||||
|        (insert-alphabetical-sorted! (list label markup-symbol text |        (insert-alphabetical-sorted! (list label markup-symbol textoptions | ||||||
|         ;; this crazy hack is necessary because lilypond depends on guile 1.8 atm |         ;; this crazy hack is necessary because lilypond depends on guile 1.8 atm | ||||||
|         ;; and so the cool unicode conversion functions cannot be used |         ;; and so the cool unicode conversion functions cannot be used | ||||||
|           (ly:string-substitute " " "" |           (ly:string-substitute " " "" | ||||||
|           (ly:string-substitute "…" "" |           (ly:string-substitute "…" "" | ||||||
|           (ly:string-substitute "Č" "C" |           (ly:string-substitute "Č" "C" | ||||||
|           (ly:string-substitute "Đ" "D" |           (ly:string-substitute "Đ" "D" | ||||||
|  |           (ly:string-substitute "Š" "S" | ||||||
|           (ly:string-substitute "Т" "T" |           (ly:string-substitute "Т" "T" | ||||||
|           (ly:string-substitute "Ä" "Ae" |           (ly:string-substitute "Ä" "Ae" | ||||||
|           (ly:string-substitute "ä" "ae" |           (ly:string-substitute "ä" "ae" | ||||||
|           (ly:string-substitute "Ö" "O" |           (ly:string-substitute "Ö" "O" | ||||||
|           (ly:string-substitute "ö" "oe" |           (ly:string-substitute "ö" "oe" | ||||||
|           (ly:string-substitute "Ü" "U" |           (ly:string-substitute "Ü" "U" | ||||||
|           (ly:string-substitute "ü" "ue" sorttext)))))))))))) |           (ly:string-substitute "ü" "ue" sorttext))))))))))))) | ||||||
|         index-item-list)) |         index-item-list)) | ||||||
|        (make-music 'EventChord |        (make-music 'EventChord | ||||||
|          'page-marker #t |          'page-marker #t | ||||||
| @@ -91,20 +92,20 @@ | |||||||
|           (cons (car ilist) (insert-alphabetical-sorted! iitem (cdr ilist)))))) |           (cons (car ilist) (insert-alphabetical-sorted! iitem (cdr ilist)))))) | ||||||
| 
 | 
 | ||||||
| % code for category index | % code for category index | ||||||
| #(define*-public (add-category-index-item! categories markup-symbol text #:optional label) #f) | #(define*-public (add-category-index-item! categories markup-symbol textoptions #:optional label) #f) | ||||||
| #(define-public (category-index-items) #f) | #(define-public (category-index-items) #f) | ||||||
| 
 | 
 | ||||||
| #(let ((category-index-hash (make-hash-table))) | #(let ((category-index-hash (make-hash-table))) | ||||||
|    (set! add-category-index-item! |    (set! add-category-index-item! | ||||||
|    (lambda* (categories markup-symbol text #:optional (label (gensym "index"))) |    (lambda* (categories markup-symbol textoptions #:optional (label (gensym "index"))) | ||||||
|      (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 category))))) |                               (list (list label 'indexCategoryMarkup `(((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 text) catlist)) |                   (cons (list label markup-symbol textoptions) catlist)) | ||||||
|                 (ly:error "song: <~a> category ~a is not defined!" (markup->string text) category)))) |                 (ly:error "song: <~a> category ~a is not defined!" (markup->string (chain-assoc-get 'rawtext textoptions)) category)))) | ||||||
|        categories) |        categories) | ||||||
|        (make-music 'EventChord |        (make-music 'EventChord | ||||||
|          'page-marker #t |          'page-marker #t | ||||||
| @@ -120,13 +121,13 @@ | |||||||
| 
 | 
 | ||||||
| #(let ((author-index-hash (make-hash-table))) | #(let ((author-index-hash (make-hash-table))) | ||||||
|    (set! add-author-index-item! |    (set! add-author-index-item! | ||||||
|    (lambda* (authorIDs markup-symbol text #:optional (label (gensym "index"))) |    (lambda* (authorIDs markup-symbol textoptions #:optional (label (gensym "index"))) | ||||||
|      (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 authorID))))) |                               (list (list label 'indexAuthorMarkup `(((rawtext . ,authorID)))))))) | ||||||
|                 (hashq-set! author-index-hash authorsym |                 (hashq-set! author-index-hash authorsym | ||||||
|                   (cons (list label markup-symbol text) authorlist)) |                   (cons (list label markup-symbol textoptions) authorlist)) | ||||||
|                 )) |                 )) | ||||||
|        authorIDs) |        authorIDs) | ||||||
|        (make-music 'EventChord |        (make-music 'EventChord | ||||||
| @@ -166,22 +167,24 @@ | |||||||
|      (markup #:override (cons 'baseline-skip 3.5) (if catname (make-left-column-markup (string-split (cadr catname) #\newline)) category))))) |      (markup #:override (cons 'baseline-skip 3.5) (if catname (make-left-column-markup (string-split (cadr catname) #\newline)) category))))) | ||||||
| 
 | 
 | ||||||
| #(define-markup-command (index-item-with-pattern layout props)() | #(define-markup-command (index-item-with-pattern layout props)() | ||||||
|  |     #:properties ((index:text "") | ||||||
|  |                   (index:alternative #f) | ||||||
|  |                   (index:page #f) | ||||||
|  |                   (line-width)) | ||||||
|     (let* ( |     (let* ( | ||||||
|             (text (chain-assoc-get 'index:text props)) |  | ||||||
|             (page (chain-assoc-get 'index:page props)) |  | ||||||
|             (width (- |             (width (- | ||||||
|                      (chain-assoc-get 'line-width props) |                      line-width | ||||||
|                      (interval-length (ly:stencil-extent (interpret-markup layout props "XXXX") X)))) |                      (interval-length (ly:stencil-extent (interpret-markup layout props "XXXX") X)))) | ||||||
|             (lines-reversed |             (lines-reversed | ||||||
|                 (if (markup? text) |  | ||||||
|                     (list text) |  | ||||||
|               (reverse (map (lambda (stil) (markup #:stencil stil)) |               (reverse (map (lambda (stil) (markup #:stencil stil)) | ||||||
|                 (wordwrap-string-internal-markup-list layout |                 (wordwrap-string-internal-markup-list layout | ||||||
|                         (cons (if (chain-assoc-get 'alternative text) |                   (prepend-alist-chain 'line-width width | ||||||
|                                 (list (cons 'line-width width) (cons 'font-shape 'italic)) |                     (if index:alternative | ||||||
|                                 (list (cons 'line-width width))) props) #f |                         (prepend-alist-chain 'font-shape 'italic props) | ||||||
|                         (chain-assoc-get 'rawtext text)))))) |                         props)) | ||||||
|             (last-line-with-dots (make-fill-with-pattern-markup 1 RIGHT "." (car lines-reversed) page)) |                   #f | ||||||
|  |                   index:text)))) | ||||||
|  |             (last-line-with-dots (make-fill-with-pattern-markup 1 RIGHT "." (car lines-reversed) index:page)) | ||||||
|             (lines-without-dots (cdr lines-reversed)) |             (lines-without-dots (cdr lines-reversed)) | ||||||
|             (target-line-size-markup |             (target-line-size-markup | ||||||
|                  (make-column-markup |                  (make-column-markup | ||||||
| @@ -203,7 +206,7 @@ | |||||||
| 
 | 
 | ||||||
| \paper { | \paper { | ||||||
|   indexItemMarkup = \markup { |   indexItemMarkup = \markup { | ||||||
|     \index-item-with-pattern |     \sans \index-item-with-pattern | ||||||
|   } |   } | ||||||
|   indexSectionMarkup = \markup \override #'(baseline-skip . 1.5) \left-column { |   indexSectionMarkup = \markup \override #'(baseline-skip . 1.5) \left-column { | ||||||
|     \sans \bold \fontsize #3 \fromproperty #'index:text |     \sans \bold \fontsize #3 \fromproperty #'index:text | ||||||
| @@ -227,12 +230,17 @@ | |||||||
| 
 | 
 | ||||||
| #(define (prepare-item-markup items layout) | #(define (prepare-item-markup items layout) | ||||||
|    (map (lambda (index-item) |    (map (lambda (index-item) | ||||||
|          (let ((label (car index-item)) |          (let* ((label (car index-item)) | ||||||
|                 (index-markup (cadr index-item)) |                 (index-markup (cadr index-item)) | ||||||
|                (text (caddr index-item))) |                 (textoptions (caddr index-item)) | ||||||
|  |                 (text (chain-assoc-get 'rawtext textoptions)) | ||||||
|  |                 (alternative (chain-assoc-get 'alternative 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:songnumber songnumber) | ||||||
|              (ly:output-def-lookup layout index-markup)))) |              (ly:output-def-lookup layout index-markup)))) | ||||||
|        (items))) |        (items))) | ||||||
| 
 | 
 | ||||||
| @@ -253,12 +261,12 @@ | |||||||
| indexItem = | indexItem = | ||||||
| #(define-music-function (parser location sorttext text) (string? markup?) | #(define-music-function (parser location sorttext text) (string? markup?) | ||||||
|    "Add a line to the alphabetical index, using the @code{indexItemMarkup} paper variable markup." |    "Add a line to the alphabetical index, using the @code{indexItemMarkup} paper variable markup." | ||||||
|    (add-index-item! 'indexItemMarkup text sorttext)) |    (add-index-item! 'indexItemMarkup (prepend-alist-chain 'rawtext text '()) sorttext)) | ||||||
| 
 | 
 | ||||||
| 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 text sorttext)) |    (add-index-item! 'indexSectionMarkup (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))) |   (let* ((headervars (hash-map->list cons (struct-ref (ly:book-header bookheader) 0))) | ||||||
| @@ -279,33 +287,36 @@ headerToTOC = #(define-music-function (parser location header label) (ly:book? s | |||||||
|             (verseComposerData (find-author-id-with-part-numbers 'meloverse authors)) |             (verseComposerData (find-author-id-with-part-numbers 'meloverse 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)) | ||||||
|             (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 bridgeIds interludeIds)) |           (append poetIds translatorIds (map car versePoetData) composerIds (map car verseComposerData) (map car voiceComposerData) compositionIds adaptionIds bridgeIds interludeIds)) | ||||||
|     )) |     )) | ||||||
|     (let* |     (let* | ||||||
|       ( |       ( | ||||||
|        (extractedheadervars (extract-and-check-vars-from-header header '(title starttext alttitle categorytitle categories authors))) |        (extractedheadervars (extract-and-check-vars-from-header header '(title starttext alttitle categorytitle categories authors songnumber))) | ||||||
|        (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)) | ||||||
|        (categorytitle (assq-ref extractedheadervars 'categorytitle)) |        (categorytitle (assq-ref extractedheadervars 'categorytitle)) | ||||||
|        (categories (assq-ref extractedheadervars 'categories)) |        (categories (assq-ref extractedheadervars 'categories)) | ||||||
|        (authors (assq-ref extractedheadervars 'authors)) |        (authors (assq-ref extractedheadervars 'authors)) | ||||||
|        (add-to-toc! (lambda (toctitle tocmarkup) |        (songnumber (assq-ref extractedheadervars 'songnumber)) | ||||||
|                       (add-index-item! 'indexItemMarkup tocmarkup toctitle label))) |        (textoptions (lambda (text alternative) `(((rawtext . ,text) (alternative . ,alternative) (songnumber . ,songnumber))))) | ||||||
|  |        (add-to-toc! (lambda (toctitle alternative) | ||||||
|  |                       (add-index-item! 'indexItemMarkup (textoptions toctitle alternative) toctitle label))) | ||||||
|        ) |        ) | ||||||
|            (if categories (add-category-index-item! (string-tokenize categories) 'indexItemMarkup (cons (list (cons 'rawtext (if categorytitle categorytitle title))) '()) 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 (cons (list (cons 'rawtext (if categorytitle categorytitle title))) '()) label)) |            (if authors (add-author-index-item! (all-author-ids authors) 'indexItemMarkup (textoptions (if categorytitle categorytitle title) #f) label)) | ||||||
|            (if starttext (add-to-toc! starttext (cons (list (cons 'rawtext starttext) (cons 'alternative #t)) '()))) |            (if starttext (add-to-toc! starttext #t)) | ||||||
|            (if alttitle |            (if alttitle | ||||||
|                (if (list? alttitle) |                (if (list? alttitle) | ||||||
|                    (for-each (lambda (alt) |                    (for-each (lambda (alt) | ||||||
|                                 (add-to-toc! alt (cons (list (cons 'rawtext alt) (cons 'alternative #t)) '()))) |                                 (add-to-toc! alt #t)) | ||||||
|                              alttitle) |                              alttitle) | ||||||
|                    (add-to-toc! alttitle (cons (list (cons 'rawtext alttitle) (cons 'alternative #t)) '())))) |                    (add-to-toc! alttitle #t))) | ||||||
|            (if title (add-to-toc! title (cons (list (cons 'rawtext title)) '())) #{ #}) |            (if title (add-to-toc! title #f) #{ #}) | ||||||
|     )) |     )) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @@ -358,7 +369,7 @@ headerToTOC = #(define-music-function (parser location header label) (ly:book? s | |||||||
|                    (songvars (cdr song)) |                    (songvars (cdr song)) | ||||||
|                    (page-number (number->string (assoc-get (assq-ref songvars 'label) labelPageTable))) |                    (page-number (number->string (assoc-get (assq-ref songvars 'label) labelPageTable))) | ||||||
|                    (extractedheadervars (extract-and-check-vars-from-header (assq-ref songvars 'header) |                    (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 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))) | ||||||
|                        (if extracted extracted "")))) |                        (if extracted extracted "")))) | ||||||
| @@ -370,6 +381,8 @@ headerToTOC = #(define-music-function (parser location header label) (ly:book? s | |||||||
|                    (verseComposerData (find-author-id-with-part-numbers 'meloverse authors)) |                    (verseComposerData (find-author-id-with-part-numbers 'meloverse 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)) | ||||||
|  |                    (adaptionMusicIds (find-author-ids-by 'adaption_music 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))) | ||||||
|               (map csv-escape |               (map csv-escape | ||||||
| @@ -385,13 +398,15 @@ headerToTOC = #(define-music-function (parser location header label) (ly:book? s | |||||||
| 
 | 
 | ||||||
|                   (headervar-or-empty 'categorytitle) |                   (headervar-or-empty 'categorytitle) | ||||||
|                   (headervar-or-empty 'categories) |                   (headervar-or-empty 'categories) | ||||||
|                   (format-authors (append poetIds (map car versePoetData))) |                   (format-authors (append poetIds adaptionTextIds (map car versePoetData))) | ||||||
|                   (format-authors translatorIds) |                   (format-authors translatorIds) | ||||||
|                   (format-authors (append composerIds compositionIds bridgeIds interludeIds (map car voiceComposerData) (map car verseComposerData))) |                   (format-authors (append composerIds compositionIds adaptionMusicIds bridgeIds interludeIds (map car voiceComposerData) (map car verseComposerData))) | ||||||
|                   (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) | ||||||
|                   (headervar-or-empty 'year_composition) |                   (headervar-or-empty 'year_composition) | ||||||
|  |                   (headervar-or-empty 'year_adaption_text) | ||||||
|  |                   (headervar-or-empty 'year_adaption_music) | ||||||
|                   (headervar-or-empty 'copyright) |                   (headervar-or-empty 'copyright) | ||||||
|                   (headervar-or-empty 'source) |                   (headervar-or-empty 'source) | ||||||
|                   (format-info-paragraphs (headervar-or-empty 'infotext)) |                   (format-info-paragraphs (headervar-or-empty 'infotext)) | ||||||
| @@ -416,6 +431,8 @@ headerToTOC = #(define-music-function (parser location header label) (ly:book? s | |||||||
|         "year_melody" |         "year_melody" | ||||||
|         "year_translation" |         "year_translation" | ||||||
|         "year_composition" |         "year_composition" | ||||||
|  |         "year_adaption_text" | ||||||
|  |         "year_adaption_music" | ||||||
|         "copyright" |         "copyright" | ||||||
|         "source" |         "source" | ||||||
|         "infotext" |         "infotext" | ||||||
							
								
								
									
										3
									
								
								public_includes/book_top.ily
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								public_includes/book_top.ily
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | \include "../private_includes/book/book_include.ily" | ||||||
|  | \include "../private_includes/book/toc_include.ily" | ||||||
|  | \include "../private_includes/book/appendix.ily" | ||||||
| @@ -26,6 +26,34 @@ TEXT = \markuplist { | |||||||
|   \TEXT |   \TEXT | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #(define TEXT_PAGES | ||||||
|  |   (map | ||||||
|  |     (lambda (text) #{ | ||||||
|  |       \markuplist { | ||||||
|  |         \override #`(transposition . ,TRANSPOSITION) | ||||||
|  |         \override #`(verselayout . ,verselayout) | ||||||
|  |         \override #`(verse-chords . ,#{ \chords { \verseChords } #}) | ||||||
|  |         \override #`(verse-reference-voice . ,#{ \global \firstVoice  #}) | ||||||
|  |         #text | ||||||
|  |       } | ||||||
|  |     #}) | ||||||
|  |   (if | ||||||
|  |     (and | ||||||
|  |       (defined? 'TEXT_PAGES) | ||||||
|  |       (pair? TEXT_PAGES)) | ||||||
|  |     TEXT_PAGES | ||||||
|  |     (list TEXT)))) | ||||||
|  | 
 | ||||||
|  | #(define (add-text-pages text-pages) | ||||||
|  |   (if (pair? text-pages) | ||||||
|  |     (begin | ||||||
|  |       (add-score (car text-pages)) | ||||||
|  |       (for-each | ||||||
|  |         (lambda (text) | ||||||
|  |           (add-music (pageBreak)) | ||||||
|  |           (add-score text)) | ||||||
|  |         (cdr text-pages))))) | ||||||
|  | 
 | ||||||
| #(if (not noStandaloneOutput) | #(if (not noStandaloneOutput) | ||||||
| (begin | (begin | ||||||
|   (let ((header (ly:book-header HEADER)) (paper (ly:book-paper HEADER))) |   (let ((header (ly:book-header HEADER)) (paper (ly:book-paper HEADER))) | ||||||
| @@ -37,7 +65,7 @@ TEXT = \markuplist { | |||||||
|       \MUSIC |       \MUSIC | ||||||
|       \layout { \LAYOUT } |       \layout { \LAYOUT } | ||||||
|     }#}) |     }#}) | ||||||
|   (add-score TEXT) |   (add-text-pages TEXT_PAGES) | ||||||
|   (add-score #{ |   (add-score #{ | ||||||
|     \score { |     \score { | ||||||
|       \unfoldRepeats { \MUSIC \INLINESCOREMUSIC } |       \unfoldRepeats { \MUSIC \INLINESCOREMUSIC } | ||||||
| @@ -1,6 +1,5 @@ | |||||||
| \version "2.25.8" |  | ||||||
| #(ly:set-option 'relative-includes #t) | #(ly:set-option 'relative-includes #t) | ||||||
| 
 | 
 | ||||||
| #(define noDefaultOutput #t) | #(define noDefaultOutput #t) | ||||||
| 
 | 
 | ||||||
| \include "all_base_includes.ly" | \include "../private_includes/base/all.ily" | ||||||
| @@ -4,4 +4,4 @@ HEADER = \bookpart { | |||||||
|     \basicSongInfo |     \basicSongInfo | ||||||
|   } |   } | ||||||
| } | } | ||||||
| \include #(if noDefaultOutput "void.ly" "standalone_output.ly") | \include #(if noDefaultOutput "../private_includes/void.ily" "layout_bottom.ily") | ||||||
| @@ -2,4 +2,4 @@ | |||||||
| 
 | 
 | ||||||
| #(define noDefaultOutput (if (defined? 'noDefaultOutput) noDefaultOutput #f)) | #(define noDefaultOutput (if (defined? 'noDefaultOutput) noDefaultOutput #f)) | ||||||
| 
 | 
 | ||||||
| \include #(if noDefaultOutput "void.ly" "all_base_includes.ly") | \include #(if noDefaultOutput "../private_includes/void.ily" "../private_includes/base/all.ily") | ||||||
| @@ -1,482 +0,0 @@ | |||||||
| ;;; (json parser) --- Guile JSON implementation. |  | ||||||
|  |  | ||||||
| ;; Copyright (C) 2013-2020 Aleix Conchillo Flaque <aconchillo@gmail.com> |  | ||||||
| ;; |  | ||||||
| ;; This file is part of guile-json. |  | ||||||
| ;; |  | ||||||
| ;; guile-json is free software: you can redistribute it and/or modify |  | ||||||
| ;; it under the terms of the GNU General Public License as published by |  | ||||||
| ;; the Free Software Foundation; either version 3 of the License, or |  | ||||||
| ;; (at your option) any later version. |  | ||||||
| ;; |  | ||||||
| ;; guile-json is distributed in the hope that it will be useful, but |  | ||||||
| ;; WITHOUT ANY WARRANTY; without even the implied warranty of |  | ||||||
| ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |  | ||||||
| ;; General Public License for more details. |  | ||||||
| ;; |  | ||||||
| ;; You should have received a copy of the GNU General Public License |  | ||||||
| ;; along with guile-json. If not, see https://www.gnu.org/licenses/. |  | ||||||
|  |  | ||||||
| ;;; Commentary: |  | ||||||
|  |  | ||||||
| ;; JSON module for Guile |  | ||||||
|  |  | ||||||
| ;;; Code: |  | ||||||
|  |  | ||||||
| (define-module (json parser) |  | ||||||
|   #:use-module (ice-9 rdelim) |  | ||||||
|   #:use-module (ice-9 streams) |  | ||||||
|   #:use-module (rnrs io ports) |  | ||||||
|   #:export (json->scm |  | ||||||
|             json-string->scm |  | ||||||
|             json-seq->scm |  | ||||||
|             json-seq-string->scm)) |  | ||||||
|  |  | ||||||
| ;; |  | ||||||
| ;; Miscellaneuos helpers |  | ||||||
| ;; |  | ||||||
|  |  | ||||||
| (define (json-exception port) |  | ||||||
|   (throw 'json-invalid port)) |  | ||||||
|  |  | ||||||
| (define (digit? c) |  | ||||||
|   (case c |  | ||||||
|     ((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9) #t) |  | ||||||
|     (else #f))) |  | ||||||
|  |  | ||||||
| (define (whitespace? c) |  | ||||||
|   (case c |  | ||||||
|     ((#\sp #\ht #\lf #\cr) #t) |  | ||||||
|     (else #f))) |  | ||||||
|  |  | ||||||
| (define (control-char? ch) |  | ||||||
|   (<= (char->integer ch) #x1F)) |  | ||||||
|  |  | ||||||
| (define (skip-whitespaces port) |  | ||||||
|   (let ((ch (peek-char port))) |  | ||||||
|     (cond |  | ||||||
|      ((whitespace? ch) |  | ||||||
|       (read-char port) |  | ||||||
|       (skip-whitespaces port)) |  | ||||||
|      (else *unspecified*)))) |  | ||||||
|  |  | ||||||
| (define (expect-string port expected return) |  | ||||||
|   (let loop ((n 0)) |  | ||||||
|     (cond |  | ||||||
|      ;; All characters match. |  | ||||||
|      ((= n (string-length expected)) return) |  | ||||||
|      ;; Go to next characters. |  | ||||||
|      ((eqv? (read-char port) (string-ref expected n)) |  | ||||||
|       (loop (+ n 1))) |  | ||||||
|      ;; Anything else is an error. |  | ||||||
|      (else (json-exception port))))) |  | ||||||
|  |  | ||||||
| (define (expect-delimiter port delimiter) |  | ||||||
|   (let ((ch (read-char port))) |  | ||||||
|     (cond |  | ||||||
|      ((not (eqv? ch delimiter)) (json-exception port)) |  | ||||||
|      ;; Unexpected EOF. |  | ||||||
|      ((eof-object? ch) (json-exception port))))) |  | ||||||
|  |  | ||||||
| (define (skip-record-separators port) |  | ||||||
|   (when (eqv? #\rs (peek-char port)) |  | ||||||
|     (read-char port) |  | ||||||
|     (skip-record-separators port))) |  | ||||||
|  |  | ||||||
| ;; |  | ||||||
| ;; Number parsing helpers |  | ||||||
| ;; |  | ||||||
|  |  | ||||||
| (define (expect-digit port) |  | ||||||
|   (let ((ch (peek-char port))) |  | ||||||
|     (cond |  | ||||||
|      ((not (digit? ch)) (json-exception port)) |  | ||||||
|      ;; Unexpected EOF. |  | ||||||
|      ((eof-object? ch) (json-exception port))))) |  | ||||||
|  |  | ||||||
| ;; Read + or -, and return 1 or -1 respectively. If something different is |  | ||||||
| ;; found, return 1. |  | ||||||
| (define (read-sign port) |  | ||||||
|   (let ((ch (peek-char port))) |  | ||||||
|     (cond |  | ||||||
|      ((eqv? ch #\+) |  | ||||||
|       (read-char port) |  | ||||||
|       1) |  | ||||||
|      ((eqv? ch #\-) |  | ||||||
|       (read-char port) |  | ||||||
|       -1) |  | ||||||
|      (else 1)))) |  | ||||||
|  |  | ||||||
| (define (read-digit-value port) |  | ||||||
|   (let ((ch (read-char port))) |  | ||||||
|     (cond |  | ||||||
|      ((eqv? ch #\0) 0) |  | ||||||
|      ((eqv? ch #\1) 1) |  | ||||||
|      ((eqv? ch #\2) 2) |  | ||||||
|      ((eqv? ch #\3) 3) |  | ||||||
|      ((eqv? ch #\4) 4) |  | ||||||
|      ((eqv? ch #\5) 5) |  | ||||||
|      ((eqv? ch #\6) 6) |  | ||||||
|      ((eqv? ch #\7) 7) |  | ||||||
|      ((eqv? ch #\8) 8) |  | ||||||
|      ((eqv? ch #\9) 9) |  | ||||||
|      (else (json-exception port))))) |  | ||||||
|  |  | ||||||
| ;; Read digits [0..9]. |  | ||||||
| (define (read-digits port) |  | ||||||
|   (expect-digit port) |  | ||||||
|   (let loop ((ch (peek-char port)) (number 0)) |  | ||||||
|     (cond |  | ||||||
|      ((digit? ch) |  | ||||||
|       (let ((value (read-digit-value port))) |  | ||||||
|         (loop (peek-char port) (+ (* number 10) value)))) |  | ||||||
|      (else number)))) |  | ||||||
|  |  | ||||||
| (define (read-digits-fraction port) |  | ||||||
|   (expect-digit port) |  | ||||||
|   (let loop ((ch (peek-char port)) (number 0) (length 0)) |  | ||||||
|     (cond |  | ||||||
|      ((digit? ch) |  | ||||||
|       (let ((value (read-digit-value port))) |  | ||||||
|         (loop (peek-char port) (+ (* number 10) value) (+ length 1)))) |  | ||||||
|      (else |  | ||||||
|       (/ number (expt 10 length)))))) |  | ||||||
|  |  | ||||||
| (define (read-exponent port) |  | ||||||
|   (let ((ch (peek-char port))) |  | ||||||
|     (cond |  | ||||||
|      ((or (eqv? ch #\e) (eqv? ch #\E)) |  | ||||||
|       (read-char port) |  | ||||||
|       (let ((sign (read-sign port)) |  | ||||||
|             (digits (read-digits port))) |  | ||||||
|         (if (<= digits 1000) ;; Some maximum exponent. |  | ||||||
|             (expt 10 (* sign digits)) |  | ||||||
|             (json-exception port)))) |  | ||||||
|      (else 1)))) |  | ||||||
|  |  | ||||||
| (define (read-fraction port) |  | ||||||
|   (let ((ch (peek-char port))) |  | ||||||
|     (cond |  | ||||||
|      ((eqv? ch #\.) |  | ||||||
|       (read-char port) |  | ||||||
|       (read-digits-fraction port)) |  | ||||||
|      (else 0)))) |  | ||||||
|  |  | ||||||
| (define (read-positive-number port) |  | ||||||
|   (let* ((number |  | ||||||
|           (let ((ch (peek-char port))) |  | ||||||
|             (cond |  | ||||||
|              ;; Numbers that start with 0 must be a fraction. |  | ||||||
|              ((eqv? ch #\0) |  | ||||||
|               (read-char port) |  | ||||||
|               0) |  | ||||||
|              ;; Otherwise read more digits. |  | ||||||
|              (else (read-digits port))))) |  | ||||||
|          (fraction (read-fraction port)) |  | ||||||
|          (exponent (read-exponent port)) |  | ||||||
|          (result (* (+ number fraction) exponent))) |  | ||||||
|     (if (and (zero? fraction) (>= exponent 1)) |  | ||||||
|         result |  | ||||||
|         (exact->inexact result)))) |  | ||||||
|  |  | ||||||
| (define (json-read-number port) |  | ||||||
|   (let ((ch (peek-char port))) |  | ||||||
|     (cond |  | ||||||
|      ;; Negative numbers. |  | ||||||
|      ((eqv? ch #\-) |  | ||||||
|       (read-char port) |  | ||||||
|       (expect-digit port) |  | ||||||
|       (* -1 (read-positive-number port))) |  | ||||||
|      ;; Positive numbers. |  | ||||||
|      ((digit? ch) |  | ||||||
|       (read-positive-number port)) |  | ||||||
|      ;; Anything else is an error. |  | ||||||
|      (else (json-exception port))))) |  | ||||||
|  |  | ||||||
| ;; |  | ||||||
| ;; Object parsing helpers |  | ||||||
| ;; |  | ||||||
|  |  | ||||||
| (define (read-pair port null ordered) |  | ||||||
|   ;; Read key. |  | ||||||
|   (let ((key (json-read-string port))) |  | ||||||
|     (skip-whitespaces port) |  | ||||||
|     (let ((ch (peek-char port))) |  | ||||||
|       (cond |  | ||||||
|        ;; Skip colon and read value. |  | ||||||
|        ((eqv? ch #\:) |  | ||||||
|         (read-char port) |  | ||||||
|         (cons key (json-read port null ordered))) |  | ||||||
|        ;; Anything other than colon is an error. |  | ||||||
|        (else (json-exception port)))))) |  | ||||||
|  |  | ||||||
| (define (json-read-object port null ordered) |  | ||||||
|   (expect-delimiter port #\{) |  | ||||||
|   (let loop ((pairs '()) (added #t)) |  | ||||||
|     (skip-whitespaces port) |  | ||||||
|     (let ((ch (peek-char port))) |  | ||||||
|       (cond |  | ||||||
|        ;; End of object. |  | ||||||
|        ((eqv? ch #\}) |  | ||||||
|         (read-char port) |  | ||||||
|         (cond |  | ||||||
|          (added (if ordered (reverse! pairs) pairs)) |  | ||||||
|          (else (json-exception port)))) |  | ||||||
|        ;; Read one pair and continue. |  | ||||||
|        ((eqv? ch #\") |  | ||||||
|         (let ((pair (read-pair port null ordered))) |  | ||||||
|           (loop (cons pair pairs) #t))) |  | ||||||
|        ;; Skip comma and read more pairs. |  | ||||||
|        ((eqv? ch #\,) |  | ||||||
|         (read-char port) |  | ||||||
|         (cond |  | ||||||
|          (added (loop pairs #f)) |  | ||||||
|          (else (json-exception port)))) |  | ||||||
|        ;; Invalid object. |  | ||||||
|        (else (json-exception port)))))) |  | ||||||
|  |  | ||||||
| ;; |  | ||||||
| ;; Array parsing helpers |  | ||||||
| ;; |  | ||||||
|  |  | ||||||
| (define (json-read-array port null ordered) |  | ||||||
|   (expect-delimiter port #\[) |  | ||||||
|   (skip-whitespaces port) |  | ||||||
|   (cond |  | ||||||
|    ;; Special case when array is empty. |  | ||||||
|    ((eqv? (peek-char port) #\]) |  | ||||||
|     (read-char port) |  | ||||||
|     #()) |  | ||||||
|    (else |  | ||||||
|     ;; Read first element in array. |  | ||||||
|     (let loop ((values (list (json-read port null ordered)))) |  | ||||||
|       (skip-whitespaces port) |  | ||||||
|       (let ((ch (peek-char port))) |  | ||||||
|         (cond |  | ||||||
|          ;; Unexpected EOF. |  | ||||||
|          ((eof-object? ch) (json-exception port)) |  | ||||||
|          ;; Handle comma (if there's a comma there should be another element). |  | ||||||
|          ((eqv? ch #\,) |  | ||||||
|           (read-char port) |  | ||||||
|           (loop (cons (json-read port null ordered) values))) |  | ||||||
|          ;; End of array. |  | ||||||
|          ((eqv? ch #\]) |  | ||||||
|           (read-char port) |  | ||||||
|           (list->vector (reverse! values))) |  | ||||||
|          ;; Anything else other than comma and end of array is wrong. |  | ||||||
|          (else (json-exception port)))))))) |  | ||||||
|  |  | ||||||
| ;; |  | ||||||
| ;; String parsing helpers |  | ||||||
| ;; |  | ||||||
|  |  | ||||||
| (define (read-hex-digit->integer port) |  | ||||||
|   (let ((ch (read-char port))) |  | ||||||
|     (cond |  | ||||||
|      ((eqv? ch #\0) 0) |  | ||||||
|      ((eqv? ch #\1) 1) |  | ||||||
|      ((eqv? ch #\2) 2) |  | ||||||
|      ((eqv? ch #\3) 3) |  | ||||||
|      ((eqv? ch #\4) 4) |  | ||||||
|      ((eqv? ch #\5) 5) |  | ||||||
|      ((eqv? ch #\6) 6) |  | ||||||
|      ((eqv? ch #\7) 7) |  | ||||||
|      ((eqv? ch #\8) 8) |  | ||||||
|      ((eqv? ch #\9) 9) |  | ||||||
|      ((or (eqv? ch #\A) (eqv? ch #\a)) 10) |  | ||||||
|      ((or (eqv? ch #\B) (eqv? ch #\b)) 11) |  | ||||||
|      ((or (eqv? ch #\C) (eqv? ch #\c)) 12) |  | ||||||
|      ((or (eqv? ch #\D) (eqv? ch #\d)) 13) |  | ||||||
|      ((or (eqv? ch #\E) (eqv? ch #\e)) 14) |  | ||||||
|      ((or (eqv? ch #\F) (eqv? ch #\f)) 15) |  | ||||||
|      (else (json-exception port))))) |  | ||||||
|  |  | ||||||
| (define (read-unicode-value port) |  | ||||||
|   (+ (* 4096 (read-hex-digit->integer port)) |  | ||||||
|       (* 256 (read-hex-digit->integer port)) |  | ||||||
|       (* 16 (read-hex-digit->integer port)) |  | ||||||
|       (read-hex-digit->integer port))) |  | ||||||
|  |  | ||||||
| ;; Unicode codepoint with surrogates is: |  | ||||||
| ;;   10000 + (high - D800) + (low - DC00) |  | ||||||
| ;; which is equivalent to: |  | ||||||
| ;;  (high << 10) + low - 35FDC00 |  | ||||||
| ;; see |  | ||||||
| ;;   https://github.com/aconchillo/guile-json/issues/58#issuecomment-662744070 |  | ||||||
| (define (json-surrogate-pair->unicode high low) |  | ||||||
|   (+ (* high #x400) low #x-35FDC00)) |  | ||||||
|  |  | ||||||
| (define (read-unicode-char port) |  | ||||||
|   (let ((codepoint (read-unicode-value port))) |  | ||||||
|     (cond |  | ||||||
|      ;; Surrogate pairs. `codepoint` already contains the higher surrogate |  | ||||||
|      ;; (between D800 and DC00) . At this point we are expecting another |  | ||||||
|      ;; \uXXXX that holds the lower surrogate (between DC00 and DFFF). |  | ||||||
|      ((and (>= codepoint #xD800) (< codepoint #xDC00)) |  | ||||||
|       (expect-string port "\\u" #f) |  | ||||||
|       (let ((low-surrogate (read-unicode-value port))) |  | ||||||
|         (if (and (>= low-surrogate #xDC00) (< low-surrogate #xE000)) |  | ||||||
|             (integer->char (json-surrogate-pair->unicode codepoint low-surrogate)) |  | ||||||
|             (json-exception port)))) |  | ||||||
|      ;; Reserved for surrogates (we just need to check starting from the low |  | ||||||
|      ;; surrogates). |  | ||||||
|      ((and (>= codepoint #xDC00) (< codepoint #xE000)) |  | ||||||
|       (json-exception port)) |  | ||||||
|      (else (integer->char codepoint))))) |  | ||||||
|  |  | ||||||
| (define (read-control-char port) |  | ||||||
|   (let ((ch (read-char port))) |  | ||||||
|     (cond |  | ||||||
|      ((eqv? ch #\") #\") |  | ||||||
|      ((eqv? ch #\\) #\\) |  | ||||||
|      ((eqv? ch #\/) #\/) |  | ||||||
|      ((eqv? ch #\b) #\bs) |  | ||||||
|      ((eqv? ch #\f) #\ff) |  | ||||||
|      ((eqv? ch #\n) #\lf) |  | ||||||
|      ((eqv? ch #\r) #\cr) |  | ||||||
|      ((eqv? ch #\t) #\ht) |  | ||||||
|      ((eqv? ch #\u) (read-unicode-char port)) |  | ||||||
|      (else (json-exception port))))) |  | ||||||
|  |  | ||||||
| (define (json-read-string port) |  | ||||||
|   (expect-delimiter port #\") |  | ||||||
|   (let loop ((chars '()) (ch (read-char port))) |  | ||||||
|     (cond |  | ||||||
|      ;; Unexpected EOF. |  | ||||||
|      ((eof-object? ch) (json-exception port)) |  | ||||||
|      ;; Unescaped control characters are not allowed. |  | ||||||
|      ((control-char? ch) (json-exception port)) |  | ||||||
|      ;; End of string. |  | ||||||
|      ((eqv? ch #\") (reverse-list->string chars)) |  | ||||||
|      ;; Escaped characters. |  | ||||||
|      ((eqv? ch #\\) |  | ||||||
|       (loop (cons (read-control-char port) chars) (read-char port))) |  | ||||||
|      ;; All other characters. |  | ||||||
|      (else |  | ||||||
|       (loop (cons ch chars) (read-char port)))))) |  | ||||||
|  |  | ||||||
| ;; |  | ||||||
| ;; Booleans and null parsing helpers |  | ||||||
| ;; |  | ||||||
|  |  | ||||||
| (define (json-read-true port) |  | ||||||
|   (expect-string port "true" #t)) |  | ||||||
|  |  | ||||||
| (define (json-read-false port) |  | ||||||
|   (expect-string port "false" #f)) |  | ||||||
|  |  | ||||||
| (define (json-read-null port null) |  | ||||||
|   (expect-string port "null" null)) |  | ||||||
|  |  | ||||||
| ;; |  | ||||||
| ;; Main parser functions |  | ||||||
| ;; |  | ||||||
|  |  | ||||||
| (define (json-read port null ordered) |  | ||||||
|   (skip-whitespaces port) |  | ||||||
|   (let ((ch (peek-char port))) |  | ||||||
|     (cond |  | ||||||
|      ;; Unexpected EOF. |  | ||||||
|      ((eof-object? ch) (json-exception port)) |  | ||||||
|      ;; Read JSON values. |  | ||||||
|      ((eqv? ch #\t) (json-read-true port)) |  | ||||||
|      ((eqv? ch #\f) (json-read-false port)) |  | ||||||
|      ((eqv? ch #\n) (json-read-null port null)) |  | ||||||
|      ((eqv? ch #\{) (json-read-object port null ordered)) |  | ||||||
|      ((eqv? ch #\[) (json-read-array port null ordered)) |  | ||||||
|      ((eqv? ch #\") (json-read-string port)) |  | ||||||
|      ;; Anything else should be a number. |  | ||||||
|      (else (json-read-number port))))) |  | ||||||
|  |  | ||||||
| ;; |  | ||||||
| ;; Public procedures |  | ||||||
| ;; |  | ||||||
|  |  | ||||||
| (define* (json->scm #:optional (port (current-input-port)) |  | ||||||
|                     #:key (null 'null) (ordered #f) (concatenated #f)) |  | ||||||
|   "Parse a JSON document into native. Takes one optional argument, |  | ||||||
| @var{port}, which defaults to the current input port from where the JSON |  | ||||||
| document is read. It also takes a few of keyword arguments: @{null}: value for |  | ||||||
| JSON's null, it defaults to the 'null symbol, @{ordered} to indicate whether |  | ||||||
| JSON objects order should be preserved or not (the default) and @{concatenated} |  | ||||||
| which can be used to tell the parser that more JSON documents might come after a |  | ||||||
| properly parsed document." |  | ||||||
|   (let loop ((value (json-read port null ordered))) |  | ||||||
|     ;; Skip any trailing whitespaces. |  | ||||||
|     (skip-whitespaces port) |  | ||||||
|     (cond |  | ||||||
|      ;; If we reach the end the parsing succeeded. |  | ||||||
|      ((eof-object? (peek-char port)) value) |  | ||||||
|      ;; If there's anything else other than the end, check if user wants to keep |  | ||||||
|      ;; parsing concatenated valid JSON documents, otherwise parser fails. |  | ||||||
|      (else |  | ||||||
|       (cond (concatenated value) |  | ||||||
|             (else (json-exception port))))))) |  | ||||||
|  |  | ||||||
| (define* (json-string->scm str #:key (null 'null) (ordered #f)) |  | ||||||
|   "Parse a JSON document into native. Takes a string argument, |  | ||||||
| @var{str}, that contains the JSON document. It also takes a couple of keyword |  | ||||||
| argument: @{null}: value for JSON's null, it defaults to the 'null symbol and |  | ||||||
| @{ordered} to indicate whether JSON objects order should be preserved or |  | ||||||
| not (the default)." |  | ||||||
|   (call-with-input-string str (lambda (p) (json->scm p #:null null #:ordered ordered)))) |  | ||||||
|  |  | ||||||
| (define* (json-seq->scm #:optional (port (current-input-port)) |  | ||||||
|                         #:key (null 'null) (ordered #f) |  | ||||||
|                         (handle-truncate 'skip) (truncated-object 'truncated)) |  | ||||||
|   "Lazy parse a JSON text sequence from the port @var{port}. |  | ||||||
| This procedure returns a stream of parsed documents. The optional argument |  | ||||||
| @var{port} defines the port to read from and defaults to the current input |  | ||||||
| port. It also takes a few keyword arguments: @{null}: value for JSON's null |  | ||||||
| (defaults to the 'null symbol), @{ordered} to indicate whether JSON objects |  | ||||||
| order should be preserved or not (the default), @{handle-truncate}: defines how |  | ||||||
| to handle data loss, @{truncated-object}: used to replace unparsable |  | ||||||
| objects. Allowed values for @{handle-truncate} argument are 'throw (throw an |  | ||||||
| exception), 'stop (stop parsing and end the stream), 'skip (default, skip |  | ||||||
| corrupted fragment and return the next entry), 'replace (skip corrupted fragment |  | ||||||
| and return @{truncated-object} instead)." |  | ||||||
|   (letrec ((handle-truncation |  | ||||||
|             (case handle-truncate |  | ||||||
|               ((throw) json-exception) |  | ||||||
|               ((stop) (const (eof-object))) |  | ||||||
|               ((skip) |  | ||||||
|                (lambda (port) |  | ||||||
|                  (read-delimited "\x1e" port 'peek) |  | ||||||
|                  (read-entry port))) |  | ||||||
|               ((replace) |  | ||||||
|                (lambda (port) |  | ||||||
|                  (read-delimited "\x1e" port 'peek) |  | ||||||
|                  truncated-object)))) |  | ||||||
|            (read-entry |  | ||||||
|             (lambda (port) |  | ||||||
|               (let ((ch (read-char port))) |  | ||||||
|                 (cond |  | ||||||
|                  ((eof-object? ch) ch) |  | ||||||
|                  ((not (eqv? ch #\rs)) |  | ||||||
|                   (handle-truncation port)) |  | ||||||
|                  (else |  | ||||||
|                   (skip-record-separators port) |  | ||||||
|                   (catch 'json-invalid |  | ||||||
|                     (lambda () |  | ||||||
|                       (let ((next (json-read port null ordered))) |  | ||||||
|                         (if (eqv? #\lf (peek-char port)) |  | ||||||
|                             (begin |  | ||||||
|                               (read-char port) |  | ||||||
|                               next) |  | ||||||
|                             (handle-truncation port)))) |  | ||||||
|                     (lambda (_ port) |  | ||||||
|                       (handle-truncation port))))))))) |  | ||||||
|     (port->stream port read-entry))) |  | ||||||
|  |  | ||||||
| (define* (json-seq-string->scm str #:key (null 'null) (ordered #f) |  | ||||||
|                                (handle-truncate 'skip) (truncated-object 'truncated)) |  | ||||||
|   "Lazy parse a JSON text sequence from the string @var{str}. |  | ||||||
| This procedure returns a stream of parsed documents and also takes the same |  | ||||||
| keyword arguments as @code{json-seq->scm}." |  | ||||||
|   (call-with-input-string str |  | ||||||
|     (lambda (p) |  | ||||||
|       (json-seq->scm p #:null null #:ordered ordered |  | ||||||
|                      #:handle-truncate handle-truncate |  | ||||||
|                      #:truncated-object truncated-object)))) |  | ||||||
|  |  | ||||||
| ;;; (json parser) ends here |  | ||||||
| @@ -1,25 +0,0 @@ | |||||||
| (if (not windows?) (use-modules (ice-9 popen))) |  | ||||||
| (use-modules (ice-9 textual-ports) (json parser)) |  | ||||||
|  |  | ||||||
| ; We use Python to convert the data yamls like the authors.yml to json, that we can parse in scheme. |  | ||||||
| ; Windows does not like Pipes, so we use a tmpfile instead. |  | ||||||
| ; Be sure you have PyYAML installed. On Windows that could be done for example like "py -m pip install PyYAML" |  | ||||||
| (define (yml-file->scm filename) |  | ||||||
|   (if windows? |  | ||||||
|     (let* ((port (make-tmpfile #f)) |  | ||||||
|             (tmpfilepath (port-filename port)) |  | ||||||
|             (ignore (close-port port)) |  | ||||||
|             (python_code (string-append "import sys, yaml, json; f = open(r'" tmpfilepath "', 'w'); f.write(json.dumps(yaml.safe_load(open(r'" filename "')))); f.close()")) |  | ||||||
|             (status (system (string-append (search-executable '("python3" "python" "py")) " -X utf8 -c \"" python_code "\""))) |  | ||||||
|             (readport (open-file tmpfilepath "r" #:encoding "UTF-8")) |  | ||||||
|             (json (get-string-all readport))) |  | ||||||
|       (close-port readport) |  | ||||||
|       (delete-file tmpfilepath) |  | ||||||
|       (json-string->scm (if (status:exit-val status) json "{}"))) |  | ||||||
|     (let* ((python_code (string-append "import sys, yaml, json; print(json.dumps(yaml.safe_load(open(r'" filename "'))))")) |  | ||||||
|             (pipe (open-pipe (string-append "PYTHONHOME='' " (search-executable '("python3" "python" "py")) " -X utf8 -c \"" python_code "\"") OPEN_READ)) |  | ||||||
|             (json (get-string-all pipe))) |  | ||||||
|       (close-pipe pipe) |  | ||||||
|       (json-string->scm json)))) |  | ||||||
|  |  | ||||||
| (define (parse-yml-file filename) (resolve-inherits (yml-file->scm filename))) |  | ||||||
							
								
								
									
										16
									
								
								styles.ly
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								styles.ly
									
									
									
									
									
								
							| @@ -1,16 +0,0 @@ | |||||||
| #(define bookStyle |  | ||||||
|   (if (not (defined? 'bookStyle)) |  | ||||||
|       #f |  | ||||||
|       bookStyle)) |  | ||||||
|  |  | ||||||
| #(define songStyle |  | ||||||
|   (if (not (defined? 'songStyle)) |  | ||||||
|       (if (not (defined? 'defaultSongStyle)) 'default defaultSongStyle) |  | ||||||
|       songStyle)) |  | ||||||
|  |  | ||||||
| #(if (not (boolean? bookStyle)) |  | ||||||
|          (set! songStyle bookStyle)) |  | ||||||
|  |  | ||||||
| #(define (bock-style layout props) |  | ||||||
|   "Whether we have bockstyle or not" |  | ||||||
|   (eq? songStyle 'bock)) |  | ||||||
		Reference in New Issue
	
	Block a user