\version "2.21.1" %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Workaround to insert one or more gaps mid-line of a score %% Fakes a system-start-delimiter at the end of every gap. %% Usage: put \space in every context at the place where you %% want the gap. %% The argument of \space determines the width of the gap. %% Needs issue 5899 and issue 5919 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Redefine "|" with a different name to allow `print-certain-span-bars?' to %% differentiate between "|" and "|-g" #(define-bar-line "|-g" "|" #f "|") space = #(define-music-function (span-bar-before width) ((boolean? #t) number?) "Adding a gap of width @var{width} into a @code{StaffSymbol}. Only works in the middle of a @code{Staff}. Before the gap starts a bar-line with span-bars covering all staves is printed unless optional @var{span-bar-before} is set false. After the gap a faked SystemStartBar covering all staves is done, i.e. @code{SpanBar} is always printed." ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; General TODO ;; Should we care about SpanBar hee at all? ;; Isn't it more due to user preferences? ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; #{ %% cadenzaOn/Off will mostly prevent line-breaks, better be paranoid \noBreak \cadenzaOn \stopStaff %% no BarNumber before gap \once \override Score.BarNumber.break-visibility = ##(#f #f #f) %% Print SpanBars relying on `span-bar-before' and %% `print-certain-span-bars' \once \override Staff.BarLine.allow-span-bar = #span-bar-before %% Insert a very short skip-event, with a stretched TextScript \once \textLengthOn s1*1/1000000-\markup \with-dimensions #(cons 0 width) #'(0 . 0) \null %% Order items after \startStaff \once \override Score.BreakAlignment.break-align-orders = #(make-vector 3 '(left-edge ambitus breathing-sign staff-bar clef key-cancellation key-signature time-signature custos)) %% Some trickery: set subproperty `new-staff' #t in order to flag this %% BarLine for the 'move-system-start'-procedure \once \override Score.BarLine.details.new-staff = ##t %\once \override StaffGroup.BarLine.details.new-staff = ##t %\once \override ChoirStaff.BarLine.details.new-staff = ##t %\once \override PianoStaff.BarLine.details.new-staff = ##f %% Use the newly defined "|-g" (apart from the name, it's the same as "|") %% and let `print-certain-span-bars' work on it, if wished. %% \bar "|-g" mimics the SystemStartBar, thus adjust thickness %% TODO We assume a new mid-staff SystemStartBarshould cover all staves %% Are there othere use-cases? \once \override Staff.BarLine.hair-thickness = 1.6 \bar "|-g" %% Force printing full-size Clef %% NB setting a different Clef is not prevented \once \override Score.Clef.full-size-change = ##t \set Staff.forceClef = ##t %% Print BarNumber after gap (for debugging purpose) %\once \override Score.BarNumber.break-visibility = ##(#f #t #t) \startStaff \cadenzaOff \noBreak #}) #(define (print-certain-span-bars? glyphes) (lambda (grob) "Predicate whether to print @code{SpanBar} at line-end/start, and to print selected span-bars from @var{glyphes} mid-line as well." (or (member (ly:grob-property grob 'glyph-name) glyphes) (not (zero? (ly:item-break-dir grob)))))) #(define (delete-duplicate-cdr lst) "Goes through @var{lst} from right to left, deletes every element which has the same @code{cdr} as the one to the right. @var{lst} should be sorted, having adjacent elements with equal @code{cdr}." (if (pair? lst) (fold-right (lambda (elem ret) (if (equal? (cdr elem) (cdr (first ret))) ret (cons elem ret))) (list (last lst)) lst) '())) #(define (move-system-start style) (lambda (grob) (let* (;; system-start-grobs are spanners, thus we need to go through ;; the broken parts (orig (if (ly:spanner? grob) (ly:grob-original grob) #f)) (siblings (if (ly:grob? orig) (ly:spanner-broken-into orig) '())) ;; padding is set to different values for different ;; system-start-grobs or not set at all ;; TODO find values programmatically (padding (case style ((bracket) 0.8) ((line-bracket) 0) ((bar-line) 0) ((brace) -0.8))) (spanner-id (ly:grob-property grob 'spanner-id)) ;; Get indent and short-indent from \paper, these values need to ;; be respected, while moving (indent (ly:output-def-lookup $defaultpaper 'indent)) (short-indent (ly:output-def-lookup $defaultpaper 'short-indent)) ;; Get output-scale from grob-layout, above (short-)indent must ;; be scaled with this value (output-scale (ly:output-def-lookup (ly:grob-layout grob) 'output-scale))) ;; Walk through all siblings ;; For each sibling find the bar-lines which indicate a mid-staff gap, ;; determine their x-coordinates and move the sibling to the selected ;; bar-line (relying on spanner-id. ;; Drop superfluous siblings. (if (pair? siblings) (for-each (lambda (sibling) (if (equal? grob sibling) (let* ((sys (ly:grob-system sibling)) (all-elts-array (ly:grob-object sys 'all-elements)) (all-elts-list (ly:grob-array->list all-elts-array)) ;; Get all bar-lines, with set details.new-staff (bar-lines (filter (lambda (elt) (and (grob::has-interface elt 'bar-line-interface) (assoc-get 'new-staff (ly:grob-property elt 'details)))) all-elts-list)) ;; Assign the x-coordinate to each found bar-line. ;; Returns a list of pairs. (bar-line-candidates (map (lambda (bl) (cons bl (ly:grob-relative-coordinate bl sys X))) bar-lines)) ;; Needed? - better be paranoid (sorted-bar-line-candidates (sort bar-line-candidates (lambda (p q) (< (cdr p) (cdr q))))) ;; Keep only one bar-line for each x-coordinate (relevant-bar-lines (delete-duplicate-cdr sorted-bar-line-candidates)) ;; Get the relevant bar-line-x-coord, by selecting ;; from relevant-bar-lines, taking spanner-id as ;; index. Return #f for spanner-id exceeding the ;; list-length. (bar-line-coord (if (> spanner-id (length relevant-bar-lines)) #f (cdr (list-ref relevant-bar-lines (1- spanner-id)))))) ;; Set the style of the system-start-grob to move. ;; Move it in front of the relevant bar-line. ;; Drop superfluous ones. (if (and (equal? grob sibling) bar-line-coord) (let ((x-off ;; Take proper scaled (short-)indent into ;; account. ;; Adjust padding. (- bar-line-coord (/ padding 2) (/ (if (equal? grob (car siblings)) indent short-indent) output-scale)))) (ly:grob-set-property! grob 'style style) (ly:grob-set-property! sibling 'X-offset x-off)) (ly:grob-suicide! sibling))))) siblings))))) #(define* (fake-mid-staff-system-start #:optional (desired-system-starts 5)) (lambda (ctx) "Constructs @code{systemStartDelimiterHierarchy} for @var{ctx}, with the default @code{systemStartDelimiter} and @var{desired-system-starts} instances of nested @code{SystemStartSquare}s. @var{desired-system-starts} will determine how many faked system-starts are possible. Collects those @code{SystemStartSquare}s and assigns a @code{spanner-id} to them. Finally assigns @code{move-system-start} to @code{after-line-breaking} of each @code{SystemStartSquare}. Limitations: - @code{SystemStartSquare}s can't be used for other things any more - A user provided @code{systemStartDelimiterHierarchy} will be dropped - Can't be reasonably consisted in score-context." (if desired-system-starts (let* ((squares '()) (system-start-delimiter (ly:context-property ctx 'systemStartDelimiter)) (style (case system-start-delimiter ((SystemStartBracket) 'bracket) ((SystemStartBrace) 'brace) ((SystemStartBar) 'bar-line) ((SystemStartSquare) 'line-bracket)))) (define (construct-system-start-delimiter main name counter init) ;; Returns a nested list like: ;; '(main ;; (name ;; (name ;; ... ;; ... ;; init))) ;; The nesting-level relies on `counter'. A negative value will ;; return an emty list. Zero returns '(main init). ;; ;; Used to construct a list for `systemStartDelimiterHierarchy' (cond ((zero? counter) (list main init)) ((negative? counter) '()) (else (construct-system-start-delimiter main name (1- counter) (cons name (list init)))))) (ly:context-set-property! ctx 'systemStartDelimiterHierarchy (construct-system-start-delimiter ;; Use default for starting system-start-delimiter ;; Which system-start-grob do we use for the inner lists 'SystemStartSquare ;; The nesting level, determines how many mid-staff-gaps get a ;; faked SystemStartDelimiter. ;; NB For zero one gap is possible etc ;; Negative values here will return an empty list (1- desired-system-starts) ;; The most inner list contains the system-start-grob to use as ;; before. ;; The numerical value determines the maximium of how many staves ;; are covered. ;; See discussion: ;; ;; TODO test with Aaron's engraver ;; DONE result: works nicely and makes it possible to reduce the ;; here provided number ;; Probably better to move this functionality out of ;; the engraver. (cons 'SystemStartSquare (iota 100)))) (make-engraver (acknowledgers ((system-start-delimiter-interface engraver grob source-engraver) ;; Always set SystemStartSquare.thickness to 0.45 to ensure ;; a sufficient thickness, if style is set 'bracket. The value ;; 0.45 is taken from IR for SystemStartBracket ;; ;; Accumulate all SystemStartSquare-grobs in `squares'. (if (eq? (grob::name grob) 'SystemStartSquare) (begin (ly:grob-set-property! grob 'thickness 0.45) (set! squares (cons grob squares)))))) ((start-translation-timestep trans) ;; Assign spanner-id to each collected SystemStartSquare (if (pair? squares) (for-each (lambda (i sq) (ly:grob-set-property! sq 'spanner-id i)) (iota (length squares) 1 1) squares))) ((finalize trans) ;; Set each SystemStartSquare.after-line-breaking to ;; `move-system-start'-procedure (for-each (lambda (sq) (ly:grob-set-property! sq 'after-line-breaking (move-system-start style))) squares) ;; Clean up (set! squares '())))) ;; don't do anything if `desired-system-starts' is #f '()))) sysStart = \with { \consists #(fake-mid-staff-system-start) } \layout { \context { \StaffGroup \sysStart } \context { \GrandStaff \sysStart } \context { \PianoStaff \sysStart } \context { \ChoirStaff \override BarLine.allow-span-bar = #(print-certain-span-bars? '("|." ".|:" ":|." "|-g")) \sysStart } \context { \Score %% adding Span_bar_engraver \consists "Span_bar_engraver" %% \sysStart does not work if consisted in Score-context } } %%%%%%%%%%%%%%%%%%%%%%%%%%%% % EXAMPLES %%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%% %% Tests %%%%%%%%%%%%%%%%%%%%%% chrds = \chordmode { c1 \space #5 d \space #5 e \break f \space #5 c \space #5 d \break e \break f \space #5 c \space #5 d \space #5 e \break f \space #5 c \space #5 d \space #5 e \space #5 f } musI = { R1 \space #5 R \space #5 R \break R \space #5 R \space #5 R \break R \break R \space #5 R \space #5 R \space #5 R \break R \space #5 R \space #5 R \space #5 R \space #5 R } testMusic = << \new Staff \musI \new Staff \musI >> \new StaffGroup \with { instrumentName = "StaffGroup" shortInstrumentName = "StGr" } << \new ChordNames \chrds \testMusic >> \markup \draw-hline \new PianoStaff \with { instrumentName = "PianoStaff" shortInstrumentName = "PiSt" } \testMusic \markup \draw-hline \new GrandStaff \with { instrumentName = "GrandStaff" shortInstrumentName = "GrSt" } \testMusic \markup \draw-hline \new ChoirStaff \with { instrumentName = "ChoirStaff" shortInstrumentName = "ChSt" } \testMusic %%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Example by Helge %%%%%%%%%%%%%%%%%%%%%%%%%%%% global = { \key es \major \time 12/8 } testSpaceI = { R1*12/8*8 \space #15 R1*12/8 } testSpaceII = { \break R1*12/8 \space #15 R1*12/8 \break R1*12/8 \space #15 R1*12/8 } tenorVoice = \relative c'' { \global \testSpaceI \break \repeat volta 2 { bes8 a bes c bes c d4. r %% probably %\once \override Score.RehearsalMark.self-alignment-X = #RIGHT \mark \markup \vcenter \smaller { "dal" \musicglyph #"scripts.segno" "al" \musicglyph #"scripts.coda" } } \space #10 \key es \major \mark \markup \smaller { \musicglyph #"scripts.coda" } bes4. bes c d | es1. \testSpaceII \bar "|." } verseTenorVoice = \lyricmode { ha -- ben wir ei -- nes er -- kannt größ -- te Schatz den's gibt. } verseTenorVoiceAlt = \lyricmode { wir a -- ber hal -- ten zu -- samm': } baritonVoice = \relative c' { \global \testSpaceI \break \repeat volta 2 { d8 d d es es es d4. r } \space #10 \key es \major << { g4. g as as g1. } \new Voice { \voiceTwo es4. es es f bes,1. } >> \testSpaceII \bar "|." } verseBaritonVoice = \lyricmode { ha -- ben wir ei -- nes er -- kannt größ -- te Schatz den's gibt. } verseBaritonVoiceAlt = \lyricmode { wir a -- ber hal -- ten zu -- samm': } bassVoice = \relative c { \global \testSpaceI \break %\once \override Staff.BarLine.allow-span-bar = ##f \repeat volta 2 { bes'8 8 8 a8 a a bes4. bes, } %\space ##f #10 \space #10 \key es \major bes'4. g f bes, es1. \testSpaceII \bar "|." } verseBassVoice = \lyricmode { \repeat unfold 7 \skip 1 Ein größ -- te Schatz den's gibt. } right = \relative c' { \global \testSpaceI \break 4. \space #10 \key es \major 4. 4. 1. \testSpaceII \bar "|." } left = \relative c { \global \testSpaceI \break bes4. f bes bes \space #10 \key es \major bes'4. g f bes, | es1. \testSpaceII \bar "|." } tenorVoicePart = << \new Voice = "tenor" \tenorVoice \new Lyrics \lyricsto "tenor" { \verseTenorVoice } \new Lyrics \lyricsto "tenor" { \verseTenorVoiceAlt } >> baritonVoicePart = << \new Voice = "bariton" \baritonVoice \new Lyrics \lyricsto "bariton" { \verseBaritonVoice } \new Lyrics \lyricsto "bariton" { \verseBaritonVoiceAlt } >> bassVoicePart = << \new Voice = "bass" { \clef bass \bassVoice } \new Lyrics \lyricsto "bass" { \verseBassVoice } >> \paper { indent = 30 short-indent = 6 } \score { << \new ChoirStaff << \new Staff \tenorVoicePart \new Staff \baritonVoicePart \new Staff \bassVoicePart >> \new PianoStaff << \new Staff \right \new Staff { \clef bass \left } >> >> }