#(define (string-replace-substring s substring replacement) "Replace every instance of substring in s by replacement." (let ((sublen (string-length substring))) (with-output-to-string (lambda () (let lp ((start 0)) (cond ((string-contains s substring start) => (lambda (end) (display (substring/shared s start end)) (display replacement) (lp (+ end sublen)))) (else (display (substring/shared s start))))))))) catScore= #(define-scheme-function (music title) (ly:music? string?) #{ \score { \header { piece = \markup { #title } } #music \layout { } } #}) catMarkup= #(define-scheme-function (text title) (markup? string?) #{ \markup { \column { \line { #title } \line { #text } \vspace #0.5 } } #}) addScore = #(define-void-function (score) (ly:score?) (add-score score)) % List contains eighter scores, or lists (score title="" count?=#t append?=#t sep="") % Set title to a string, {idx} is replaced by current count. Set count?=#f to not count % the current score, e.g. Ex. 2 and Ex. 2b. Set append?=#f to not append title to Ex. {idx}, % but to replace it. If append?=#t you may sep sep as Separator between Ex. {idx} and title % can also take nested pairs (score title count append . sep) % % if score is music it is counted by default, if markup not % if score is markup we replace the title by default catScores= #(define-void-function (listOfScores i) (list? number?) (if (not (null? listOfScores)) (let* ( (current (car listOfScores)) (score (if (and (not (markup? current)) (pair? current)) (car current) current)) (rest1 (if (and (not (markup? current)) (pair? current)) (cdr current) '())) (fmt (if (null? rest1) "" (if (pair? rest1) (car rest1) rest1))) (rest2 (if (pair? rest1) (cdr rest1) '())) (count? (if (null? rest2) (ly:music? score) (if (pair? rest2) (car rest2) rest2))) (rest3 (if (pair? rest2) (cdr rest2) '())) (append? (if (null? rest3) (ly:music? score) (if (pair? rest3) (car rest3) rest3))) (rest4 (if (pair? rest3) (cdr rest3) '())) (sep (if (null? rest4) "" (if (pair? rest4) (car rest4) rest4))) (fmt-real (if append? (string-join (list "Ex. {idx}" fmt) sep) fmt)) (title (string-replace-substring fmt-real "{idx}" (if count? (+ 1 i) i))) ) (if (ly:music? score) (add-score (catScore score title)) (add-text (catMarkup score title))) (catScores (cdr listOfScores) (if count? (+ 1 i) i))))) #(define catA (list #{ \markup\justify{ This Category contains Examples of very shady nature. Practise them with care, or they might eat your furniture! You’ve been warned! Really! This is the last chance to turn back!} #} #{ c'4 e'8 e' g' f' e'4 #} #{ d'4 4 16 16 e'8 g' d' #} #{ e'8 8 f' f' d' d' g4 #} (markup #:justify ( "This" "example" "has" "two" "unrelated" "subexamples." "Don’t" "ask" "for" "the" "reason ...")) (list #{ c'4 e'8 e' g' f' e'4 #} "b" #f) ; do not count and append b (list #{ d'4 4 16 16 e'8 g' d' #} "Example {idx}" #t #f) ; count and replace (list #{ \markup\justify{ A counted markup with title.} #} "" #t #t) (list #{ e'8 8 f' f' d' d' g4 #} "The Title" #t #t ": ") ; count, append, use : as sep )) \markup "Only printing one category this time" \catScores #catA 0 #(define catB (list #{ \time 2/3 \times 2/3 { f'4 g' a' e' } #} #{ \new StaffGroup << \new Staff { c'8 d' e' f' e' d' c'4 } \new Staff {\clef bass c4 g f e } >> #} #{ \new TabStaff { e, g b e' } #})) printCats= #(define-void-function (listOfCategories) (list?) (if (not (null? listOfCategories)) (begin (add-text #{ \markup\column{\larger\larger\larger\line { Category #(car (car listOfCategories)) } \vspace #0.6 } #}) (catScores (cdr (car listOfCategories)) 0) (printCats (cdr listOfCategories))))) #(define cats (list (cons "A" catA) (cons "B" catB))) \bookpart { \markup "Printing all categories" \printCats #cats }