Initial import
[orchestrallily.git] / orchestrallily.ly
blob32b9ebd0e0f99c0cfee9f58a7c7ca6165bd1510b
1 \version "2.11.41"
3 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4 % OrchestralLily
5 % ==============
6 % Desciption: Lilypond package to make writing large orchestral scores easier.
7 % Documentation: http://wiki.kainhofer.com/lilypond/orchestrallily
8 % Version: 0.01, 2008-03-02
9 % Author: Reinhold Kainhofer, reinhold@kainhofer.com
10 % Copyright: (C) 2008 by Reinhold Kainhofer
11 % License: GPL v3.0, http://www.gnu.org/licenses/gpl.html
12 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
14 #(use-modules (ice-9 match))
17 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
18 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
19 %%%%% SCORE STRUCTURE AND AUTOMATIC GENERATION
20 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
21 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
26 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
27 % Helper functions
28 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
30 % Helper function to filter all non-null entries
31 #(define (not-null? x) (not (null? x)))
33 % Helper function to extract a given variable, built from [Piece][Instrument]Identifier
34 #(define (namedPieceInstrObject piece instr name)
35 (let* (
36 (fullname (string->symbol (string-append piece instr name)))
37 (instrname (string->symbol (string-append instr name)))
38 (piecename (string->symbol (string-append piece name)))
40 (cond
41 ((defined? fullname) (primitive-eval fullname))
42 ((defined? instrname) (primitive-eval instrname))
43 ((defined? piecename) (primitive-eval piecename))
44 (else '())
49 %% Print text as a justified paragraph, taken from the lilypond Notation Reference
50 #(define-markup-list-command (paragraph layout props args) (markup-list?)
51 (let ((indent (chain-assoc-get 'par-indent props 2)))
52 (interpret-markup-list layout props
53 (make-justified-lines-markup-list (cons (make-hspace-markup indent)
54 args)))))
56 conditionalBreak = #(define-music-function (parser location) ()
57 #{ \tag #'instrumental-score \pageBreak #}
60 #(define (oly:piece-title-markup title) (markup #:column (#:line (#:fontsize #'3 #:bold title))) )
62 #(define-markup-command (piece-title layout props title) (markup?)
63 ; (toc-item title)
64 (interpret-markup layout props (oly:piece-title-markup title))
67 #(define (oly:generate_object_name piece instr obj )
68 (if (and (string? piece) (string? instr) (string? obj))
69 (string-append piece instr obj)
73 #(define (oly:generate_staff_name piece instr) (oly:generate_object_name piece instr "St"))
75 #(define (set-context-property context property value)
76 (set! (ly:music-property context property) value)
80 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
81 % Score structure
82 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
84 #(define oly:orchestral_score_structure '())
86 #(define (oly:set_score_structure struct)
87 (if (list? struct)
88 (set! oly:orchestral_score_structure struct)
89 (ly:warning (_ "oly:set_score_structure needs an association list as argument!"))
93 orchestralScoreStructure = #(define-music-function (parser location structure) (list?)
94 (oly:set_score_structure structure)
95 (make-music 'Music 'void #t)
99 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
100 % Automatic staff and group generation
101 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
103 % Retrieve all music definitions for the given
104 #(define (oly:get_music_objects piece name instruments)
105 (filter not-null? (map (lambda (i) (namedPieceInstrObject piece i "Music")) instruments))
108 #(define (oly:make_staff_internal piece name music)
109 (let* (
110 (tempo (namedPieceInstrObject piece name "Tempo"))
111 (lyrics (namedPieceInstrObject piece name "Lyrics"))
112 (musiccontent '())
114 ;(ly:message "Music in make_staff_internal (piece=~S, name=~S)" piece name)
116 (if (ly:music? lyrics)
117 (set! musiccontent (append musiccontent (list dynamicUp)))
118 (if (not-null? lyrics) (ly:warning (_ "Wrong type (no lyrics) for lyrics for instrument ~S in piece ~S") name piece))
120 ; Append the settings, key and clef (if defined)
121 (map
122 (lambda (type)
123 (let* ((object (namedPieceInstrObject piece name type)))
124 (if (ly:music? object)
125 (set! musiccontent (append musiccontent (list object)))
126 (if (not-null? object) (ly:warning (_ "Wrong type (no ly:music) for ~S for instrument ~S in piece ~S") type name piece))
130 '("Settings" "Key" "Clef")
133 (if (ly:music? music)
134 (begin
135 (set! musiccontent (append musiccontent (list music)))
136 ;(ly:message "Generating staff for ~a" name)
138 (let* (
139 (voicename (oly:generate_object_name piece name "Voice" ))
140 (staffname (oly:generate_staff_name piece name))
141 (voice (context-spec-music (make-simultaneous-music musiccontent) 'Voice voicename))
142 (staff '())
143 (staffcont (list voice))
144 (propops (oly:make_staff_properties piece name))
146 ; If we have lyrics, create a lyrics context containing LyricCombineMusic
147 ; and add that as second element to the staff's elements list...
148 (if (ly:music? lyrics)
149 (let* (
150 (lyricsname (oly:generate_object_name piece name "Lyrics" ))
151 (lyricscont (make-music 'LyricCombineMusic 'element lyrics 'associated-context voicename))
153 (set! staffcont (append staffcont
154 (list (context-spec-music lyricscont 'Lyrics lyricsname))))
157 (set! staff (context-spec-music (make-simultaneous-music staffcont) 'Staff staffname))
158 (if (not-null? propops)
159 (set! (ly:music-property staff 'property-operations) propops)
161 staff
164 ; For empty music, return empty
170 % TODO: Implement one-staff with multiple voices (\voiceOne and \voiceTwo),
171 % possibly with lyrics attached
172 #(define (oly:make_multi_voice_staff parser piece instr voices)
173 (ly:message "Generating a staff with multiple voices is not yet implemented, using 'SimultaneousMusic instead. Staff ID: ~a, voices: ~a" instr voices)
174 (oly:make_parallel_staves parser piece instr voices)
177 #(define (oly:make_staff parser piece instr)
178 (let* ( (music (namedPieceInstrObject piece instr "Music")) )
179 ;(ly:message "make_staff: ~S ~S" piece instr)
180 (if (not-null? music)
181 (oly:make_staff_internal piece instr music)
187 #(define (oly:make_parallel_staves parser piece instr instruments)
188 (let* (
189 (staves (map (lambda (i) (oly:create_staff_or_group parser piece i)) instruments))
190 (nonemptystaves (filter not-null? staves))
192 (if (not-null? nonemptystaves)
193 (make-simultaneous-music nonemptystaves)
199 #(define (oly:make_part_combined_staff parser piece instr instruments)
200 (let* ((music (oly:get_music_objects piece instr instruments)))
201 ;(ly:message "make_part_combined_staff: ~S ~S ~a" piece instr instruments)
202 (cond
203 ((and (pair? music) (ly:music? (car music)) (not-null? (cdr music)) (ly:music? (cadr music)))
204 ;(ly:message "Part-combine with two music expressions")
205 (oly:make_staff_internal piece instr (make-part-combine-music parser music)))
206 ((null? music)
207 ;(ly:message "Part-combine without any music expressions")
208 '())
209 ; exactly one is a music expression, simply use that by joining
210 ((list? music)
211 ;(ly:message "Part-combine with only one music expressions")
212 (oly:make_staff_internal piece instr (apply append music)))
213 (else
214 ;(ly:message "make_part_combined_staff: ~S ~S ~a" piece instr instruments)
215 '() )
220 #(define (oly:create_staff_or_group parser piece instr)
221 (let* ( (staff (namedPieceInstrObject piece instr "Staff")) )
222 ;(if (not-null? staff)
223 ; (ly:message "Found staff variable for instrument ~a in piece ~a" instr piece)
224 ; (ly:message "Staff variable for instrument ~a in piece ~a NOT FOUND" instr piece)
226 (if (not-null? staff)
227 ; Explicit staff variable, use that
228 staff
229 ; no staff defined => check hierarchy definition and match a possible entry
230 ; against the four allowed forms
231 (match (assoc-ref oly:orchestral_score_structure instr)
232 ; type (ParallelMusic|SimultaneousMusic ("sub" "instruments"...))
233 ; generate << ... >>
234 ( ((or 'ParallelMusic 'SimultaneousMusic) (? list? subinstr))
235 (oly:make_parallel_staves parser piece instr subinstr) )
237 ; type (StaffGroupType ("sub" "instruments"...)), generate staff group
238 ( ((? symbol? stafftype) (? list? subinstr))
239 (oly:make_staff_group parser piece instr stafftype subinstr) )
241 ; type (#t ("sub" "instruments")) => part-combined staff
242 ( (#t ((? string? instone) (? string? insttwo)))
243 (oly:make_part_combined_staff parser piece instr (list instone insttwo)) )
245 ; type (#f ("sub" "instruments")) => staff with multiple voices
246 ( (#f (? list? subinstr))
247 (oly:make_multi_voice_staff parser piece instr subinstr) )
249 ; not found in score history -> simple staff
250 ( #f
251 (oly:make_staff parser piece instr) )
253 ; Any other type is invalid, treat it like a simple staff!
254 ( invalidform
255 (ly:warning (_ "Encountered illegal entry ~S in score structure for instrument ~a") invalidform instr)
256 (ly:warning (_ "Trying to interpret ~S as a simple instrument") instr)
257 (oly:make_staff parser piece instr) )
263 % Generate the properties for the staff for piece and instr. Typically, these
264 % are the instrument name and the short instrument name (if defined).
265 % return a (possibly empty) list of all assignments.
266 #(define (oly:make_staff_properties piece instr)
267 (let* (
268 (instrName (namedPieceInstrObject piece instr "InstrumentName"))
269 (shortInstrName (namedPieceInstrObject piece instr "ShortInstrumentName"))
270 (props '())
272 (if (not-null? instrName)
273 (set! props (append props (list (list 'assign 'instrumentName instrName)))))
274 (if (not-null? shortInstrName)
275 (set! props (append props (list (list 'assign 'shortInstrumentName shortInstrName)))))
276 props
279 #(define (oly:settings_pair setting value)
280 (if (not-null? value)
281 (list setting value)
285 #(define (oly:make_staff_group parser piece instr stafftype instruments)
286 (let* (
287 (staves (oly:make_parallel_staves parser piece instr instruments))
289 (if (not-null? staves)
290 (let* (
291 (staffname (oly:generate_staff_name piece instr))
292 (group (context-spec-music staves stafftype staffname))
293 (propops (oly:make_staff_properties piece instr))
295 (set! (ly:music-property group 'property-operations) propops)
296 group
298 ; Return empty list if no staves are generated
305 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
306 % Automatic score generation
307 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
309 #(define oly:score_handler collect-scores-for-book)
310 useBook = #(define-music-function (parser location usebook) (boolean?)
311 (if usebook
312 (set! oly:score_handler book-score-handler)
313 (set! oly:score_handler toplevel-score-handler)
315 (make-music 'Music 'void #t)
319 % post-filter functions. By default, no filtering is done. However,
320 % for the *NoCues* function, the cue notes should be killed
321 identity = #(define-music-function (parser location music) (ly:music?) music)
322 cuefilter = #(define-music-function (parser location music) (ly:music?)
323 ((ly:music-function-extract removeWithTag) parser location 'cued ((ly:music-function-extract killCues) parser location music))
326 % The helper function to build a score.
327 #(define (createScoreHelper parser location part instr func)
328 (let* (
329 (staves (oly:make_parallel_staves parser part "topLevel" instr))
330 (music (if (not-null? staves)
331 ((ly:music-function-extract func) parser location staves)
334 (score '())
335 (piecename (namedPieceInstrObject part (car instr) "PieceName"))
336 (piecenametacet (namedPieceInstrObject part (car instr) "PieceNameTacet"))
337 (header '())
339 ; Set the piecename in the header and apply it to the score
340 ;(display-lily-music music parser)
341 ;(display-scheme-music music)
342 (if (null? music)
343 ; No staves, print tacet
344 (begin
345 (if (not-null? piecenametacet) (set! piecename piecenametacet))
346 (if (not-null? piecename)
347 (collect-scores-for-book parser (list (oly:piece-title-markup piecename)))
348 (ly:warning (_ "No music and no score title found for part ~a and instrument ~a") part instr)
351 ; we have staves, apply the piecename to the score
352 (begin
353 (set! header (make-module))
354 (if (not-null? piecename)
355 (module-define! header 'piece piecename) )
356 (set! score (scorify-music music parser))
357 (ly:score-set-header! score header)
358 ; Schedule the score for typesetting
359 (collect-scores-for-book parser score)
363 ; This is a void function, the score has been schedulled for typesetting already
364 (make-music 'Music 'void #t)
366 createScore = #(define-music-function (parser location piece instr) (string? list?)
367 (createScoreHelper parser location piece instr identity)
369 createNoCuesScore = #(define-music-function (parser location piece instr) (string? list?)
370 (createScoreHelper parser location piece instr cuefilter)
377 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
378 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
379 %%%%% CUE NOTES
380 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
381 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
383 % set the cue instrument name
384 setCue = #(define-music-function (parser location instr) (string?)
385 #{ \set Voice.instrumentCueName = $instr #} )
387 % generate a cue music section with instrument names
388 % Parameters: \namedCueDuring NameOfQuote CueDirection CueInstrument OriginalInstrument music
389 % -) NameOfQuote CueDirection music are the parameters for \cueDuring
390 % -) CueInstrument and OriginalInstrument are the displayed instrument names
391 % typical call:
392 % \namedCueDuring #"vIQuote" #UP #"V.I" #"Sop." { R1*3 }
393 % This adds the notes from vIQuote (defined via \addQuote) to three measures, prints "V.I" at
394 % the beginning of the cue notes and "Sop." at the end
395 namedCueDuring = #(define-music-function (parser location cuevoice direction instrcue instr cuemusic) (string? number? string? string? ly:music?)
397 \cueDuring #$cuevoice #$direction { \tag #'cued \setCue #$instrcue $cuemusic \tag #'cued \setCue #$instr }
398 % \tag #'uncued $cuemusic
401 namedTransposedCueDuring = #(define-music-function (parser location cuevoice direction instrcue instr trans cuemusic) (string? number? string? string? ly:music? ly:music?)
403 \transposedCueDuring #$cuevoice #$direction $trans { \tag #'cued \setCue #$instrcue $cuemusic \tag #'cued \setCue #$instr }
404 % \tag #'uncued $cuemusic
408 % set the cue instrument name and clef
409 setClefCue = #(define-music-function (parser location instr clef)
410 (string? ly:music?)
412 \once \override Staff.Clef #'font-size = #-3 $clef
413 \set Voice.instrumentCueName = $instr
414 #} )
416 % generate a cue music section with instrument names and clef changes
417 % Parameters: \cleffedCueDuring NameOfQuote CueDirection CueInstrument CueClef OriginalInstrument OriginalClef music
418 % -) NameOfQuote CueDirection music are the parameters for \cueDuring
419 % -) CueInstrument and OriginalInstrument are the displayed instrument names
420 % -) CueClef and OriginalClef are the clefs for the the cue notes and the clef of the containing voice
421 % typical call:
422 % \cleffedCueDuring #"vIQuote" #UP #"V.I" #"treble" #"Basso" #"bass" { R1*3 }
423 % This adds the notes from vIQuote (defined via \addQuote) to three measures, prints "V.I" at
424 % the beginning of the cue notes and "Basso" at the end. The clef is changed to treble at the
425 % beginning of the cue notes and reset to bass at the end
426 cleffedCueDuring = #(define-music-function (parser location cuevoice direction instrcue clefcue instr clefinstr cuemusic)
427 (string? number? string? ly:music? string? ly:music? ly:music?)
429 \cueDuring #$cuevoice #$direction { \tag #'cued \setClefCue #$instrcue $clefcue $cuemusic \tag #'cued \setClefCue #$instr $clefinstr }
430 % \tag #'uncued $cuemusic
437 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
438 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
439 %%%%% DYNAMICS
440 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
441 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
443 tempoMark = #(define-music-function (parser location padding marktext) (number? string?)
445 \once \override Score . RehearsalMark #'padding = $padding
446 \mark \markup { \bold \smaller $marktext }
449 shiftDynamics = #(define-music-function (parser location xshift yshift) (number? number?)
451 \once \override DynamicTextSpanner #'padding = $yshift
452 \once\override DynamicText #'extra-offset = #(cons $xshift $yshift)
455 ffz = #(make-dynamic-script "ffz")
456 pf = #(make-dynamic-script "pf")
457 sempp = #(make-dynamic-script (markup #:line( #:with-dimensions '(0 . 0)
458 '(0 . 0) #:right-align #:normal-text #:italic "sempre" #:dynamic "pp")))
459 parenf = #(make-dynamic-script (markup #:line(#:normal-text #:italic #:fontsize 2 "(" #:dynamic "f" #:normal-text #:italic #:fontsize 2 ")" )))
460 parenp = #(make-dynamic-script (markup #:line(#:normal-text #:italic #:fontsize 2 "(" #:dynamic "p" #:normal-text #:italic #:fontsize 2 ")" )))
464 dim = #(make-span-event 'DecrescendoEvent START)
465 enddim = #(make-span-event 'DecrescendoEvent STOP)
466 decresc = #(make-span-event 'DecrescendoEvent START)
467 enddecresc = #(make-span-event 'DecrescendoEvent STOP)
468 cresc = #(make-span-event 'CrescendoEvent START)
469 endcresc = #(make-span-event 'CrescendoEvent STOP)
471 setCresc = {
472 \set crescendoText = \markup { \italic "cresc." }
473 \set crescendoSpanner = #'dashed-line
475 setDecresc = {
476 \set decrescendoText = \markup { \italic "decresc." }
477 \set decrescendoSpanner = #'dashed-line
479 setDim = {
480 \set decrescendoText = \markup { \italic "dim." }
481 \set decrescendoSpanner = #'dashed-line
484 newOrOldClef = #(define-music-function (parser location new old ) (string? string?)
485 (if (ly:get-option 'old-clefs) #{ \clef $old #} #{ \clef $new #})
490 %%% Thanks to "Gilles THIBAULT" <gilles.thibault@free.fr>, there is a way
491 % to remove also the fermata from R1-\fermataMarkup: By filtering the music
492 % and removing the corresponding events.
493 % Documented as an LSR snippet: http://lsr.dsi.unimi.it/LSR/Item?id=372
494 #(define (filterOneEventsMarkup event)
495 ( let ( (eventname (ly:music-property event 'name)) )
496 (not
497 (or ;; add here event name you do NOT want
498 (eq? eventname 'MultiMeasureTextEvent)
499 (eq? eventname 'AbsoluteDynamicEvent)
500 (eq? eventname 'TextScriptEvent)
501 (eq? eventname 'ArticulationEvent)
502 (eq? eventname 'CrescendoEvent)
503 (eq? eventname 'DecrescendoEvent)
508 filterArticulations = #(define-music-function (parser location music) (ly:music?)
509    (music-filter filterOneEventsMarkup music)
522 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
523 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
524 %%%%% REST COMBINATION
525 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
526 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
530 %% REST COMBINING, TAKEN FROM http://lsr.dsi.unimi.it/LSR/Item?id=336
532 %% Usage:
533 %% \new Staff \with {
534 %% \override RestCollision #'positioning-done = #merge-rests-on-positioning
535 %% } << \somevoice \\ \othervoice >>
536 %% or (globally):
537 %% \layout {
538 %% \context {
539 %% \Staff
540 %% \override RestCollision #'positioning-done = #merge-rests-on-positioning
541 %% }
542 %% }
544 %% Limitations:
545 %% - only handles two voices
546 %% - does not handle multi-measure/whole-measure rests
548 #(define (rest-score r)
549 (let ((score 0)
550 (yoff (ly:grob-property-data r 'Y-offset))
551 (sp (ly:grob-property-data r 'staff-position)))
552 (if (number? yoff)
553 (set! score (+ score 2))
554 (if (eq? yoff 'calculation-in-progress)
555 (set! score (- score 3))))
556 (and (number? sp)
557 (<= 0 2 sp)
558 (set! score (+ score 2))
559 (set! score (- score (abs (- 1 sp)))))
560 score))
562 #(define (merge-rests-on-positioning grob)
563 (let* ((can-merge #f)
564 (elts (ly:grob-object grob 'elements))
565 (num-elts (and (ly:grob-array? elts)
566 (ly:grob-array-length elts)))
567 (two-voice? (= num-elts 2)))
568 (if two-voice?
569 (let* ((v1-grob (ly:grob-array-ref elts 0))
570 (v2-grob (ly:grob-array-ref elts 1))
571 (v1-rest (ly:grob-object v1-grob 'rest))
572 (v2-rest (ly:grob-object v2-grob 'rest)))
573 (and
574 (ly:grob? v1-rest)
575 (ly:grob? v2-rest)
576 (let* ((v1-duration-log (ly:grob-property v1-rest 'duration-log))
577 (v2-duration-log (ly:grob-property v2-rest 'duration-log))
578 (v1-dot (ly:grob-object v1-rest 'dot))
579 (v2-dot (ly:grob-object v2-rest 'dot))
580 (v1-dot-count (and (ly:grob? v1-dot)
581 (ly:grob-property v1-dot 'dot-count -1)))
582 (v2-dot-count (and (ly:grob? v2-dot)
583 (ly:grob-property v2-dot 'dot-count -1))))
584 (set! can-merge
585 (and
586 (number? v1-duration-log)
587 (number? v2-duration-log)
588 (= v1-duration-log v2-duration-log)
589 (eq? v1-dot-count v2-dot-count)))
590 (if can-merge
591 ;; keep the rest that looks best:
592 (let* ((keep-v1? (>= (rest-score v1-rest)
593 (rest-score v2-rest)))
594 (rest-to-keep (if keep-v1? v1-rest v2-rest))
595 (dot-to-kill (if keep-v1? v2-dot v1-dot)))
596 ;; uncomment if you're curious of which rest was chosen:
597 ;;(ly:grob-set-property! v1-rest 'color green)
598 ;;(ly:grob-set-property! v2-rest 'color blue)
599 (ly:grob-suicide! (if keep-v1? v2-rest v1-rest))
600 (if (ly:grob? dot-to-kill)
601 (ly:grob-suicide! dot-to-kill))
602 (ly:grob-set-property! rest-to-keep 'direction 0)
603 (ly:rest::y-offset-callback rest-to-keep)))))))
604 (if can-merge
606 (ly:rest-collision::calc-positioning-done grob))))
615 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
616 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
617 %%%%% TITLE PAGE / HEADER
618 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
619 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
622 \paper {
623 scoreTitleMarkup = \markup \piece-title \fromproperty #'header:piece
624 bookTitleMarkup = \markup {
625 \override #'(baseline-skip . 3.5)
626 \column {
627 \override #'(baseline-skip . 3.5)
628 \column {
629 \huge \bigger \bold
630 \fill-line {
631 \bigger \fromproperty #'header:title
633 \fill-line {
634 \large \smaller \bold
635 \bigger \fromproperty #'header:subtitle
637 \fill-line {
638 \smaller \bold
639 \fromproperty #'header:subsubtitle
641 \fill-line {
642 { \large \bold \fromproperty #'header:instrument }
644 \fill-line {
645 \fromproperty #'header:poet
646 \fromproperty #'header:composer
648 \fill-line {
649 \fromproperty #'header:meter
650 \fromproperty #'header:arranger
662 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
663 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
664 %%%%% SCORE (HEADER / LAYOUT) SETTINGS
665 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
666 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
668 \paper {
669 left-margin = 2\cm
670 right-margin = 2\cm
671 line-width = 17\cm
672 % after-title-space = 0.5\cm
673 ragged-bottom = ##f
674 ragged-last-bottom = ##f
676 \layout {
677 \context {
678 \ChoirStaff
679 % If only one non-empty staff in a system exists, still print the backet
680 \override SystemStartBracket #'collapse-height = #1
682 \context {
683 \StaffGroup
684 % If only one non-empty staff in a system exists, still print the backet
685 \override SystemStartBracket #'collapse-height = #1
687 \context {
688 \Score
689 % Force multi-measure rests to be written as one span
690 \override MultiMeasureRest #'expand-limit = #3
691 skipBars = ##t
692 autoBeaming = ##f
693 hairpinToBarline = ##f
694 \override BarNumber #'break-visibility = #end-of-line-invisible
695 \override CombineTextScript #'avoid-slur = #'outside
696 barNumberVisibility = #(every-nth-bar-number-visible 5)
697 \override DynamicTextSpanner #'dash-period = #-1.0
698 \override InstrumentSwitch #'font-size = #-1
700 % Rest collision
701 \override RestCollision #'positioning-done = #merge-rests-on-positioning
702 % Auto-Accidentals: Use modern-cautionary style...
703 extraNatural = ##f
704 autoAccidentals = #'(Staff (same-octave . 0))
705 autoCautionaries = #'(Staff (any-octave . 0) (same-octave . 1))
706 printKeyCancellation = ##t
708 \context {
709 \RemoveEmptyStaffContext
711 \context {
712 \Lyrics
713 \override VerticalAxisGroup #'minimum-Y-extent = #'(0.5 . 0.5)
715 \context {
716 \StaffGroup
717 \consists "Instrument_name_engraver"