1 ;;; define-music-display-methods.scm -- data for displaying music
2 ;;; expressions using LilyPond notation.
4 ;;; Copyright (C) 2005--2015 Nicolas Sceaux <nicolas.sceaux@free.fr>
7 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
9 ;;; Display method implementation
12 (define-module (scm display-lily))
17 (define (scheme-expr->lily-string scm-arg)
18 (cond ((or (number? scm-arg)
21 (format #f "~s" scm-arg))
22 ((or (symbol? scm-arg)
24 (format #f "'~s" scm-arg))
27 (or (procedure-name scm-arg)
28 (with-output-to-string
30 (pretty-print (procedure-source scm-arg)))))))
33 (with-output-to-string
35 (display-scheme-music scm-arg)))))))
40 (define-public (markup->lily-string markup-expr)
41 "Return a string describing, in LilyPond syntax, the given markup
43 (define (proc->command proc)
44 (let ((cmd-markup (symbol->string (procedure-name proc))))
45 (substring cmd-markup 0 (- (string-length cmd-markup)
46 (string-length "-markup")))))
47 (define (arg->string arg)
50 ((markup? arg) ;; a markup
51 (markup->lily-string-aux arg))
52 ((and (pair? arg) (every markup? arg)) ;; a markup list
53 (format #f "{~{ ~a~}}" (map-in-order markup->lily-string-aux arg)))
54 (else ;; a scheme argument
55 (format #f "#~a" (scheme-expr->lily-string arg)))))
56 (define (markup->lily-string-aux expr)
59 (let ((cmd (car expr))
61 (if (eqv? cmd simple-markup) ;; a simple markup
62 (format #f "~s" (car args))
63 (format #f "\\~a~{ ~a~}"
65 (map-in-order arg->string args))))))
66 (cond ((string? markup-expr)
67 (format #f "~s" markup-expr))
68 ((eqv? (car markup-expr) simple-markup)
69 (format #f "~s" (second markup-expr)))
71 (format #f "\\markup ~a"
72 (markup->lily-string-aux markup-expr)))))
78 ;; It is a pity that there is no rassoc in Scheme.
79 (define* (rassoc item alist #:optional (test equal?))
80 (do ((alist alist (cdr alist))
82 ((or result (null? alist)) result)
83 (if (and (car alist) (test item (cdar alist)))
84 (set! result (car alist)))))
86 (define-public (note-name->lily-string ly-pitch)
87 ;; here we define a custom pitch= function, since we do not want to
88 ;; test whether octaves are also equal. (otherwise, we would be using equal?)
89 (define (pitch= pitch1 pitch2)
90 (and (= (ly:pitch-notename pitch1) (ly:pitch-notename pitch2))
91 (= (ly:pitch-alteration pitch1) (ly:pitch-alteration pitch2))))
92 (let* ((pitches (if parser (ly:parser-lookup 'pitchnames)
93 (assoc-get (string->symbol default-language)
94 language-pitch-names '())))
95 (result (rassoc ly-pitch pitches pitch=)))
96 (and result (car result))))
98 (define-public (octave->lily-string pitch)
99 (let ((octave (ly:pitch-octave pitch)))
101 (make-string (1+ octave) #\'))
103 (make-string (1- (* -1 octave)) #\,))
109 (define*-public (duration->lily-string ly-duration #:key
111 (time-scale (*time-scale*)))
112 (let ((log2 (ly:duration-log ly-duration))
113 (dots (ly:duration-dot-count ly-duration))
114 (scale (ly:duration-scale ly-duration)))
115 (if (or force-duration (not (*omit-duration*)))
116 (string-append (case log2
120 (else (number->string (expt 2 log2))))
121 (make-string dots #\.)
122 (let ((end-scale (/ scale time-scale)))
123 (if (= end-scale 1) ""
124 (format #f "*~a" end-scale))))
131 (define (post-event? m)
132 (music-is-of-type? m 'post-event))
134 (define* (event-direction->lily-string event #:optional (required #t))
135 (let ((direction (ly:music-property event 'direction)))
136 (cond ((or (not direction) (null? direction) (= CENTER direction))
137 (if required "-" ""))
138 ((= UP direction) "^")
139 ((= DOWN direction) "_")
142 (define-macro (define-post-event-display-method type vars direction-required str)
143 `(define-display-method ,type ,vars
145 (event-direction->lily-string ,(car vars) ,direction-required)
148 (define-macro (define-span-event-display-method type vars direction-required str-start str-stop)
149 `(define-display-method ,type ,vars
151 (event-direction->lily-string ,(car vars) ,direction-required)
152 (if (= START (ly:music-property ,(car vars) 'span-direction))
156 (define-display-method HyphenEvent (event parser)
158 (define-display-method ExtenderEvent (event parser)
160 (define-display-method TieEvent (event parser)
162 (define-display-method BeamForbidEvent (event parser)
164 (define-display-method StringNumberEvent (event parser)
165 (format #f "\\~a" (ly:music-property event 'string-number)))
168 (define-display-method TremoloEvent (event parser)
169 (let ((tremolo-type (ly:music-property event 'tremolo-type 8)))
170 (format #f ":~a" tremolo-type)))
172 (define-display-method ArticulationEvent (event parser) #t
173 (let* ((articulation (ly:music-property event 'articulation-type))
175 (case (string->symbol articulation)
179 ((staccatissimo) "!")
184 (format #f "~a~:[\\~;~]~a"
185 (event-direction->lily-string event shorthand)
187 (or shorthand articulation))))
189 (define-post-event-display-method FingeringEvent (event parser) #t
190 (ly:music-property event 'digit))
192 (define-post-event-display-method TextScriptEvent (event parser) #t
193 (markup->lily-string (ly:music-property event 'text)))
195 (define-post-event-display-method MultiMeasureTextEvent (event parser) #t
196 (markup->lily-string (ly:music-property event 'text)))
198 (define-post-event-display-method BendAfterEvent (event parser) #f
199 (format #f "\\bendAfter #~a " (ly:music-property event 'delta-step)))
201 (define-post-event-display-method HarmonicEvent (event parser) #f "\\harmonic")
202 (define-post-event-display-method GlissandoEvent (event parser) #f "\\glissando")
203 (define-post-event-display-method ArpeggioEvent (event parser) #f "\\arpeggio")
204 (define-post-event-display-method AbsoluteDynamicEvent (event parser) #f
205 (format #f "\\~a" (ly:music-property event 'text)))
207 (define-post-event-display-method StrokeFingerEvent (event parser) #f
208 (format #f "\\rightHandFinger #~a " (ly:music-property event 'digit)))
210 (define-span-event-display-method BeamEvent (event parser) #f "[" "]")
211 (define-span-event-display-method SlurEvent (event parser) #f "(" ")")
212 (define-span-event-display-method CrescendoEvent (event parser) #f "\\<" "\\!")
213 (define-span-event-display-method DecrescendoEvent (event parser) #f "\\>" "\\!")
214 (define-span-event-display-method EpisemaEvent (event parser) #f "\\episemInitium" "\\episemFinis")
215 (define-span-event-display-method PhrasingSlurEvent (event parser) #f "\\(" "\\)")
216 (define-span-event-display-method SustainEvent (event parser) #f "\\sustainOn" "\\sustainOff")
217 (define-span-event-display-method SostenutoEvent (event parser) #f "\\sostenutoOn" "\\sostenutoOff")
218 (define-span-event-display-method TextSpanEvent (event parser) #f "\\startTextSpan" "\\stopTextSpan")
219 (define-span-event-display-method TrillSpanEvent (event parser) #f "\\startTrillSpan" "\\stopTrillSpan")
220 (define-span-event-display-method StaffSpanEvent (event parser) #f "\\startStaff" "\\stopStaff")
221 (define-span-event-display-method NoteGroupingEvent (event parser) #f "\\startGroup" "\\stopGroup")
222 (define-span-event-display-method UnaCordaEvent (event parser) #f "\\unaCorda" "\\treCorde")
228 (define-display-method GraceMusic (expr parser)
229 (format #f "\\grace ~a"
230 (music->lily-string (ly:music-property expr 'element))))
232 ;; \acciaccatura \appoggiatura \grace
233 ;; TODO: it would be better to compare ?start and ?stop
234 ;; with startAppoggiaturaMusic and stopAppoggiaturaMusic,
235 ;; using a custom music equality predicate.
236 (define-extra-display-method GraceMusic (expr parser)
237 "Display method for appoggiatura."
238 (with-music-match (expr (music
245 ;; we check whether ?start and ?stop look like
246 ;; startAppoggiaturaMusic stopAppoggiaturaMusic
247 (and (with-music-match (?start (music
254 span-direction START))))))
256 (with-music-match (?stop (music
263 span-direction STOP))))))
264 (format #f "\\appoggiatura ~a" (music->lily-string ?music))))))
267 (define-extra-display-method GraceMusic (expr parser)
268 "Display method for acciaccatura."
269 (with-music-match (expr (music
276 ;; we check whether ?start and ?stop look like
277 ;; startAcciaccaturaMusic stopAcciaccaturaMusic
278 (and (with-music-match (?start (music
285 span-direction START)))
290 grob-property-path '(stroke-style)
294 (with-music-match (?stop (music
300 grob-property-path '(stroke-style)
308 span-direction STOP))))))
309 (format #f "\\acciaccatura ~a" (music->lily-string ?music))))))
311 (define-extra-display-method GraceMusic (expr parser)
312 "Display method for grace."
313 (with-music-match (expr (music
320 ;; we check whether ?start and ?stop look like
321 ;; startGraceMusic stopGraceMusic
322 (and (null? (ly:music-property ?start 'elements))
323 (null? (ly:music-property ?stop 'elements))
324 (format #f "\\grace ~a" (music->lily-string ?music)))))
330 (define-display-method SequentialMusic (seq parser)
331 (let ((force-line-break (and (*force-line-break*)
333 (> (length (ly:music-property seq 'elements))
334 (*max-element-number-before-break*))))
335 (elements (ly:music-property seq 'elements))
336 (chord? (make-music-type-predicate 'EventChord))
337 (note-or-chord? (make-music-type-predicate 'EventChord 'NoteEvent
338 'LyricEvent 'RestEvent
340 (cluster? (make-music-type-predicate 'ClusterNoteEvent))
341 (note? (make-music-type-predicate 'NoteEvent)))
342 (format #f "~a~a{~v%~v_~{~a~^ ~}~v%~v_}"
346 (any cluster? (ly:music-property e 'elements)))))
350 (if (*explicit-mode*)
351 ;; if the sequence contains EventChord which contains figures ==> figuremode
352 ;; if the sequence contains EventChord which contains lyrics ==> lyricmode
353 ;; if the sequence contains EventChord which contains drum notes ==> drummode
354 (cond ((any (lambda (chord)
355 (any (make-music-type-predicate 'BassFigureEvent)
356 (ly:music-property chord 'elements)))
357 (filter chord? elements))
359 ((any (lambda (chord)
360 (any (make-music-type-predicate 'LyricEvent)
362 (ly:music-property chord 'elements))))
363 (filter note-or-chord? elements))
365 ((any (lambda (chord)
368 (not (null? (ly:music-property event 'drum-type)))))
370 (ly:music-property chord 'elements))))
371 (filter note-or-chord? elements))
373 (else ;; TODO: other modes?
376 (if force-line-break 1 0)
377 (if force-line-break (+ 2 (*indent*)) 1)
378 (parameterize ((*indent* (+ 2 (*indent*))))
379 (map-in-order (lambda (music)
380 (music->lily-string music))
382 (if force-line-break 1 0)
383 (if force-line-break (*indent*) 1))))
385 (define-display-method SimultaneousMusic (sim parser)
386 (parameterize ((*indent* (+ 3 (*indent*))))
387 (format #f "<< ~{~a ~}>>"
388 (map-in-order (lambda (music)
389 (music->lily-string music))
390 (ly:music-property sim 'elements)))))
392 (define-extra-display-method SimultaneousMusic (expr parser)
393 "If `sim' is an \afterGrace expression, return \"\\afterGrace ...\".
394 Otherwise, return #f."
395 ;; TODO: do something with afterGraceFraction?
396 (with-music-match (expr (music 'SimultaneousMusic
397 elements (?before-grace
398 (music 'SequentialMusic
399 elements ((music 'SkipMusic)
402 (format #f "\\afterGrace ~a ~a"
403 (music->lily-string ?before-grace)
404 (music->lily-string ?grace))))
410 (define-display-method EventChord (chord parser)
411 ;; event_chord : command_element
412 ;; | note_chord_element
414 ;; TODO : tagged post_events
415 ;; post_events : ( post_event | tagged_post_event )*
416 ;; tagged_post_event: '-' \tag embedded_scm post_event
418 (let* ((elements (append (ly:music-property chord 'elements)
419 (ly:music-property chord 'articulations)))
420 (chord-repeat (ly:music-property chord 'duration)))
423 (partition (lambda (m) (music-is-of-type? m 'rhythmic-event))
425 (lambda (chord-elements other-elements)
426 (cond ((pair? chord-elements)
427 ;; note_chord_element :
428 ;; '<' (notepitch | drumpitch)* '>" duration post_events
429 (let ((duration (duration->lily-string (ly:music-property
432 ;; Format duration first so that it does not appear on
434 (format #f "< ~{~a ~}>~a~:{~:[-~;~]~a~^ ~}"
435 (parameterize ((*omit-duration* #t))
438 (music->lily-string music))
441 (map-in-order (lambda (music)
444 (music->lily-string music)))
446 ((ly:duration? chord-repeat)
447 (let ((duration (duration->lily-string chord-repeat)))
448 (format #f "q~a~:{~:[-~;~]~a~^ ~}"
450 (map-in-order (lambda (music)
453 (music->lily-string music)))
456 ((and (= 1 (length other-elements))
457 (not (post-event? (car other-elements))))
458 (format #f (music->lily-string (car other-elements))))
460 (format #f "< >~:{~:[-~;~]~a~^ ~}"
461 (map-in-order (lambda (music)
464 (music->lily-string music)))
465 other-elements))))))))
467 (define-display-method MultiMeasureRestMusic (mmrest parser)
468 (format #f "R~a~{~a~^ ~}"
469 (duration->lily-string (ly:music-property mmrest 'duration))
470 (map-in-order (lambda (music)
471 (music->lily-string music))
472 (ly:music-property mmrest 'articulations))))
474 (define-display-method SkipMusic (skip parser)
475 (format #f "\\skip ~a" (duration->lily-string (ly:music-property skip 'duration) #:force-duration #t)))
477 (define-display-method OttavaMusic (ottava parser)
478 (format #f "\\ottava #~a" (ly:music-property ottava 'ottava-number)))
481 ;;; Notes, rests, skips...
484 (define (simple-note->lily-string event parser)
485 (format #f "~a~a~a~a~a~a~:{~:[-~;~]~a~}" ; pitchname octave !? octave-check duration optional_rest articulations
486 (note-name->lily-string (ly:music-property event 'pitch))
487 (octave->lily-string (ly:music-property event 'pitch))
488 (let ((forced (ly:music-property event 'force-accidental))
489 (cautionary (ly:music-property event 'cautionary)))
490 (cond ((and (not (null? forced))
492 (not (null? cautionary))
495 ((and (not (null? forced)) forced) "!")
497 (let ((octave-check (ly:music-property event 'absolute-octave)))
498 (if (not (null? octave-check))
499 (format #f "=~a" (cond ((>= octave-check 0)
500 (make-string (1+ octave-check) #\'))
502 (make-string (1- (* -1 octave-check)) #\,))
505 (duration->lily-string (ly:music-property event 'duration))
506 (if ((make-music-type-predicate 'RestEvent) event)
508 (map-in-order (lambda (event)
511 (music->lily-string event)))
512 (ly:music-property event 'articulations))))
514 (define-display-method NoteEvent (note parser)
515 (cond ((not (null? (ly:music-property note 'pitch))) ;; note
516 (simple-note->lily-string note parser))
517 ((not (null? (ly:music-property note 'drum-type))) ;; drum
518 (format #f "~a~a~{~a~}" (ly:music-property note 'drum-type)
519 (duration->lily-string (ly:music-property note 'duration))
520 (map-in-order (lambda (event)
521 (music->lily-string event))
522 (ly:music-property note 'articulations))))
525 (format #f "~a~{~a~}"
526 (duration->lily-string (ly:music-property note 'duration)
528 (map-in-order (lambda (event)
529 (music->lily-string event))
530 (ly:music-property note 'articulations))))))
532 (define-display-method ClusterNoteEvent (note parser)
533 (simple-note->lily-string note parser))
535 (define-display-method RestEvent (rest parser)
536 (if (not (null? (ly:music-property rest 'pitch)))
537 (simple-note->lily-string rest parser)
538 (format #f "r~a~{~a~}"
539 (duration->lily-string (ly:music-property rest 'duration))
540 (map-in-order (lambda (event)
541 (music->lily-string event))
542 (ly:music-property rest 'articulations)))))
544 (define-display-method MultiMeasureRestEvent (rest parser)
545 (string-append "R" (duration->lily-string (ly:music-property rest 'duration))))
547 (define-display-method SkipEvent (rest parser)
548 (format #f "s~a~{~a~}"
549 (duration->lily-string (ly:music-property rest 'duration))
550 (map-in-order (lambda (event)
551 (music->lily-string event))
552 (ly:music-property rest 'articulations))))
554 (define-display-method RepeatedChord (chord parser)
555 (music->lily-string (ly:music-property chord 'element)))
557 (define-display-method MarkEvent (mark parser)
558 (let ((label (ly:music-property mark 'label)))
561 (format #f "\\mark ~a" (markup->lily-string label)))))
563 (define-display-method KeyChangeEvent (key parser)
564 (let ((pitch-alist (ly:music-property key 'pitch-alist))
565 (tonic (ly:music-property key 'tonic)))
566 (if (or (null? pitch-alist)
569 (let ((c-pitch-alist (ly:transpose-key-alist pitch-alist
570 (ly:pitch-diff (ly:make-pitch 0 0 0) tonic))))
571 (format #f "\\key ~a \\~a~a"
572 (note-name->lily-string (ly:music-property key 'tonic))
575 (equal? (ly:parser-lookup mode) c-pitch-alist))
576 (symbol->string mode)
578 '(major minor ionian locrian aeolian mixolydian lydian phrygian dorian))
579 (new-line->lily-string))))))
581 (define-display-method RelativeOctaveCheck (octave parser)
582 (let ((pitch (ly:music-property octave 'pitch)))
583 (format #f "\\octaveCheck ~a~a"
584 (note-name->lily-string pitch)
585 (octave->lily-string pitch))))
587 (define-display-method VoiceSeparator (sep parser)
590 (define-display-method LigatureEvent (ligature parser)
591 (if (= START (ly:music-property ligature 'span-direction))
595 (define-display-method BarCheck (check parser)
596 (format #f "|~a" (new-line->lily-string)))
598 (define-display-method PesOrFlexaEvent (expr parser)
601 (define-display-method BassFigureEvent (figure parser)
602 (let ((alteration (ly:music-property figure 'alteration))
603 (fig (ly:music-property figure 'figure))
604 (bracket-start (ly:music-property figure 'bracket-start))
605 (bracket-stop (ly:music-property figure 'bracket-stop)))
607 (format #f "~a~a~a~a"
608 (if (null? bracket-start) "" "[")
609 (cond ((null? fig) "_")
610 ((markup? fig) (second fig)) ;; fig: (<number-markup> "number")
612 (if (null? alteration)
615 ((= alteration DOUBLE-FLAT) "--")
616 ((= alteration FLAT) "-")
617 ((= alteration NATURAL) "!")
618 ((= alteration SHARP) "+")
619 ((= alteration DOUBLE-SHARP) "++")
621 (if (null? bracket-stop) "" "]"))))
623 (define-display-method LyricEvent (lyric parser)
624 (format #f "~a~{~a~^ ~}"
625 (let ((text (ly:music-property lyric 'text)))
626 (if (or (string? text)
627 (eqv? (first text) simple-markup))
628 ;; a string or a simple markup
629 (let ((string (if (string? text)
632 (if (string-match "(\"| |[0-9])" string)
633 ;; TODO check exactly in which cases double quotes should be used
634 (format #f "~s" string)
636 (markup->lily-string text)))
637 (map-in-order (lambda (m) (music->lily-string m))
638 (ly:music-property lyric 'articulations))))
640 (define-display-method BreathingEvent (event parser)
647 (define-display-method AutoChangeMusic (m parser)
648 (format #f "\\autochange ~a"
649 (music->lily-string (ly:music-property m 'element))))
651 (define-display-method ContextChange (m parser)
652 (format #f "\\change ~a = \"~a\""
653 (ly:music-property m 'change-to-type)
654 (ly:music-property m 'change-to-id)))
658 (define-display-method TimeScaledMusic (times parser)
659 (let* ((num (ly:music-property times 'numerator))
660 (den (ly:music-property times 'denominator))
661 (span (ly:music-property times 'duration #f))
662 ;; need to format before changing time scale
664 (and span (duration->lily-string span #:force-duration #t)))
666 (time-scale (*time-scale*)))
668 (parameterize ((*force-line-break* #f)
669 (*time-scale* (* time-scale scale)))
670 (format #f "\\tuplet ~a/~a ~@[~a ~]~a"
674 (music->lily-string (ly:music-property times 'element))))))
677 (define-display-method RelativeOctaveMusic (m parser)
678 (music->lily-string (ly:music-property m 'element)))
680 (define-display-method TransposedMusic (m parser)
681 (music->lily-string (ly:music-property m 'element)))
687 (define-display-method AlternativeEvent (alternative parser) "")
689 (define (repeat->lily-string expr repeat-type parser)
690 (let* ((main (music->lily-string (ly:music-property expr 'element))))
691 (format #f "\\repeat ~a ~a ~a ~a"
693 (ly:music-property expr 'repeat-count)
695 (let ((alternatives (ly:music-property expr 'elements)))
696 (if (null? alternatives)
698 (format #f "\\alternative { ~{~a ~}}"
699 (map-in-order (lambda (music)
700 (music->lily-string music))
703 (define-display-method VoltaRepeatedMusic (expr parser)
704 (repeat->lily-string expr "volta" parser))
706 (define-display-method UnfoldedRepeatedMusic (expr parser)
707 (repeat->lily-string expr "unfold" parser))
709 (define-display-method PercentRepeatedMusic (expr parser)
710 (repeat->lily-string expr "percent" parser))
712 (define-display-method TremoloRepeatedMusic (expr parser)
713 (repeat->lily-string expr "tremolo" parser))
719 (define-display-method ContextSpeccedMusic (expr parser)
720 (let ((id (ly:music-property expr 'context-id))
721 (create-new (ly:music-property expr 'create-new))
722 (music (ly:music-property expr 'element))
723 (operations (ly:music-property expr 'property-operations))
724 (ctype (ly:music-property expr 'context-type)))
725 (format #f "~a ~a~a~a ~a"
726 (if (and (not (null? create-new)) create-new)
732 (format #f " = ~s" id))
733 (if (null? operations)
735 (format #f " \\with {~{~a~}~%~v_}"
736 (parameterize ((*indent* (+ (*indent*) 2)))
738 (format #f "~%~v_\\~a ~s"
744 (parameterize ((*current-context* ctype))
745 (music->lily-string music)))))
747 ;; special cases: \figures \lyrics \drums
748 (define-extra-display-method ContextSpeccedMusic (expr parser)
749 (with-music-match (expr (music 'ContextSpeccedMusic
751 property-operations ?op
752 context-type ?context-type
755 (parameterize ((*explicit-mode* #f))
758 (format #f "\\figures ~a" (music->lily-string ?sequence)))
760 (format #f "\\lyrics ~a" (music->lily-string ?sequence)))
762 (format #f "\\drums ~a" (music->lily-string ?sequence)))
767 ;;; Context properties
769 (define-extra-display-method ContextSpeccedMusic (expr parser)
770 (let ((element (ly:music-property expr 'element))
771 (property-tuning? (make-music-type-predicate 'PropertySet
775 (sequence? (make-music-type-predicate 'SequentialMusic)))
776 (if (and (ly:music? element)
777 (or (property-tuning? element)
778 (and (sequence? element)
779 (every property-tuning? (ly:music-property element 'elements)))))
780 (parameterize ((*current-context* (ly:music-property expr 'context-type)))
781 (music->lily-string element))
784 (define-public (value->lily-string arg)
785 (cond ((ly:music? arg)
786 (music->lily-string arg))
788 (format #f "#~s" arg))
790 (markup->lily-string arg))
792 (format #f "##{ ~a #}" (duration->lily-string arg #:force-duration #t)))
795 (note-name->lily-string arg)
796 (octave->lily-string arg)))
798 (format #f "#~a" (scheme-expr->lily-string arg)))))
800 (define-display-method PropertySet (expr parser)
801 (let ((property (ly:music-property expr 'symbol))
802 (value (ly:music-property expr 'value))
803 (once (ly:music-property expr 'once)))
804 (format #f "~a\\set ~a~a = ~a~a"
805 (if (and (not (null? once)))
808 (if (eqv? (*current-context*) 'Bottom)
810 (format #f "~a . " (*current-context*)))
812 (value->lily-string value)
813 (new-line->lily-string))))
815 (define-display-method PropertyUnset (expr parser)
816 (format #f "\\unset ~a~a~a"
817 (if (eqv? (*current-context*) 'Bottom)
819 (format #f "~a . " (*current-context*)))
820 (ly:music-property expr 'symbol)
821 (new-line->lily-string)))
823 ;;; Layout properties
825 (define-display-method OverrideProperty (expr parser)
826 (let* ((symbol (ly:music-property expr 'symbol))
827 (properties (ly:music-property expr 'grob-property-path
828 (list (ly:music-property expr 'grob-property))))
829 (value (ly:music-property expr 'grob-value))
830 (once (ly:music-property expr 'once)))
832 (format #f "~a\\override ~{~a~^.~} = ~a~a"
837 (if (eqv? (*current-context*) 'Bottom)
838 (cons symbol properties)
839 (cons* (*current-context*) symbol properties))
840 (value->lily-string value)
841 (new-line->lily-string))))
843 (define-display-method RevertProperty (expr parser)
844 (let* ((symbol (ly:music-property expr 'symbol))
845 (properties (ly:music-property expr 'grob-property-path
846 (list (ly:music-property expr 'grob-property)))))
847 (format #f "\\revert ~{~a~^.~}~a"
848 (if (eqv? (*current-context*) 'Bottom)
849 (cons symbol properties)
850 (cons* (*current-context*) symbol properties))
851 (new-line->lily-string))))
853 (define-display-method TimeSignatureMusic (expr parser)
854 (let* ((num (ly:music-property expr 'numerator))
855 (den (ly:music-property expr 'denominator))
856 (structure (ly:music-property expr 'beat-structure)))
857 (if (null? structure)
861 (new-line->lily-string))
863 "\\time #'~a ~a/~a~a"
865 (new-line->lily-string)))))
867 ;;; \melisma and \melismaEnd
868 (define-extra-display-method ContextSpeccedMusic (expr parser)
869 "If expr is a melisma, return \"\\melisma\", otherwise, return #f."
870 (with-music-match (expr (music 'ContextSpeccedMusic
871 element (music 'PropertySet
873 symbol 'melismaBusy)))
876 (define-extra-display-method ContextSpeccedMusic (expr parser)
877 "If expr is a melisma end, return \"\\melismaEnd\", otherwise, return #f."
878 (with-music-match (expr (music 'ContextSpeccedMusic
879 element (music 'PropertyUnset
880 symbol 'melismaBusy)))
884 (define-extra-display-method SequentialMusic (expr parser)
885 (with-music-match (expr (music 'SequentialMusic
886 elements ((music 'TempoChangeEvent
889 metronome-count ?count)
890 (music 'ContextSpeccedMusic
891 element (music 'PropertySet
892 symbol 'tempoWholesPerMinute)))))
893 (format #f "\\tempo ~{~a~a~}~a = ~a~a"
895 (list (markup->lily-string ?text) " ")
897 (duration->lily-string ?unit #:force-duration #t)
899 (format #f "~a - ~a" (car ?count) (cdr ?count))
901 (new-line->lily-string))))
903 (define-display-method TempoChangeEvent (expr parser)
904 (let ((text (ly:music-property expr 'text)))
905 (format #f "\\tempo ~a~a"
906 (markup->lily-string text)
907 (new-line->lily-string))))
910 (define clef-name-alist #f)
911 (define-public (memoize-clef-names clefs)
912 "Initialize @code{clef-name-alist}, if not already set."
913 (if (not clef-name-alist)
914 (set! clef-name-alist
915 (map (lambda (name+vals)
916 (cons (cdr name+vals)
920 (define-extra-display-method ContextSpeccedMusic (expr parser)
921 "If @var{expr} is a clef change, return \"\\clef ...\".
922 Otherwise, return @code{#f}."
923 (with-music-match (expr (music 'ContextSpeccedMusic
925 element (music 'SequentialMusic
926 elements ((music 'PropertySet
930 symbol 'middleCClefPosition)
933 symbol 'clefPosition)
935 value ?clef-transposition
936 symbol 'clefTransposition)
938 value ?clef-transposition-style
939 symbol 'clefTranspositionStyle)
941 procedure ly:set-middle-C!)))))
942 (let ((clef-name (assoc-get (list ?clef-glyph ?clef-position 0)
945 (format #f "\\clef \"~a~?\"~a"
947 (case ?clef-transposition-style
948 ((parenthesized) "~a(~a)")
949 ((bracketed) "~a[~a]")
951 (cond ((zero? ?clef-transposition)
953 ((positive? ?clef-transposition)
954 (list "^" (1+ ?clef-transposition)))
955 (else (list "_" (- 1 ?clef-transposition))))
956 (new-line->lily-string))))))
959 (define-extra-display-method ContextSpeccedMusic (expr parser)
960 "If `expr' is a bar, return \"\\bar ...\".
961 Otherwise, return #f."
962 (with-music-match (expr (music 'ContextSpeccedMusic
964 element (music 'PropertySet
967 (format #f "\\bar \"~a\"~a" ?bar-type (new-line->lily-string))))
970 (define-extra-display-method ContextSpeccedMusic (expr parser)
971 "If `expr' is a partial measure, return \"\\partial ...\".
972 Otherwise, return #f."
973 (with-music-match (expr (music
980 duration ?duration))))
983 (format #f "\\partial ~a"
984 (duration->lily-string ?duration #:force-duration #t)))))
989 (define-display-method ApplyOutputEvent (applyoutput parser)
990 (let ((proc (ly:music-property applyoutput 'procedure))
991 (ctx (ly:music-property applyoutput 'context-type)))
992 (format #f "\\applyOutput #'~a #~a"
994 (or (procedure-name proc)
995 (with-output-to-string
997 (pretty-print (procedure-source proc))))))))
999 (define-display-method ApplyContext (applycontext parser)
1000 (let ((proc (ly:music-property applycontext 'procedure)))
1001 (format #f "\\applyContext #~a"
1002 (or (procedure-name proc)
1003 (with-output-to-string
1005 (pretty-print (procedure-source proc))))))))
1008 (define-display-method PartCombineMusic (expr parser)
1009 (format #f "\\partcombine ~{~a ~}"
1010 (map-in-order (lambda (music)
1011 (music->lily-string music))
1012 (ly:music-property expr 'elements))))
1014 (define-extra-display-method PartCombineMusic (expr parser)
1015 (with-music-match (expr (music 'PartCombineMusic
1017 elements ((music 'UnrelativableMusic
1018 element (music 'ContextSpeccedMusic
1021 element ?sequence1))
1022 (music 'UnrelativableMusic
1023 element (music 'ContextSpeccedMusic
1026 element ?sequence2)))))
1027 (format #f "\\partcombine~a ~a~a~a"
1028 (cond ((equal? ?dir UP) "Up")
1029 ((equal? ?dir DOWN) "Down")
1031 (music->lily-string ?sequence1)
1032 (new-line->lily-string)
1033 (music->lily-string ?sequence2))))
1035 (define-extra-display-method ContextSpeccedMusic (expr parser)
1036 "If `expr' is a \\partcombine expression, return \"\\partcombine ...\".
1037 Otherwise, return #f."
1039 (expr (music 'ContextSpeccedMusic
1041 element (music 'SimultaneousMusic
1042 elements ((music 'ContextSpeccedMusic
1044 context-type 'Voice)
1045 (music 'ContextSpeccedMusic
1047 context-type 'Voice)
1048 (music 'ContextSpeccedMusic
1050 context-type 'Voice)
1051 (music 'ContextSpeccedMusic
1053 context-type 'Voice)
1054 (music 'ContextSpeccedMusic
1056 context-type 'NullVoice)
1059 (?pc-music (music 'PartCombineMusic))
1060 (format #f "~a" (music->lily-string ?pc-music)))))
1062 (define-display-method UnrelativableMusic (expr parser)
1063 (music->lily-string (ly:music-property expr 'element)))
1066 (define-display-method QuoteMusic (expr parser)
1067 (or (with-music-match (expr (music
1069 quoted-voice-direction ?quoted-voice-direction
1070 quoted-music-name ?quoted-music-name
1071 quoted-context-id "cue"
1072 quoted-context-type 'CueVoice
1074 (format #f "\\cueDuring #~s #~a ~a"
1076 ?quoted-voice-direction
1077 (music->lily-string ?music)))
1078 (format #f "\\quoteDuring #~s ~a"
1079 (ly:music-property expr 'quoted-music-name)
1080 (music->lily-string (ly:music-property expr 'element)))))
1085 (define-display-method LineBreakEvent (expr parser)
1086 (if (null? (ly:music-property expr 'break-permission))
1090 (define-display-method PageBreakEvent (expr parser)
1091 (if (null? (ly:music-property expr 'break-permission))
1095 (define-display-method PageTurnEvent (expr parser)
1096 (if (null? (ly:music-property expr 'break-permission))
1100 (define-extra-display-method EventChord (expr parser)
1101 (with-music-match (expr (music 'EventChord
1102 elements ((music 'LineBreakEvent
1103 break-permission 'force)
1104 (music 'PageBreakEvent
1105 break-permission 'force))))
1108 (define-extra-display-method EventChord (expr parser)
1109 (with-music-match (expr (music 'EventChord
1110 elements ((music 'LineBreakEvent
1111 break-permission 'force)
1112 (music 'PageBreakEvent
1113 break-permission 'force)
1114 (music 'PageTurnEvent
1115 break-permission 'force))))
1123 (define-display-method LyricCombineMusic (expr parser)
1124 (format #f "\\lyricsto ~s ~a"
1125 (ly:music-property expr 'associated-context)
1126 (parameterize ((*explicit-mode* #f)
1127 (*omit-duration* #t))
1128 (music->lily-string (ly:music-property expr 'element)))))
1131 (define-extra-display-method SimultaneousMusic (expr parser)
1132 (with-music-match (expr (music 'SimultaneousMusic
1133 elements ((music 'ContextSpeccedMusic
1136 element ?note-sequence)
1137 (music 'ContextSpeccedMusic
1138 context-type 'Lyrics
1140 element (music 'LyricCombineMusic
1141 associated-context ?associated-id
1142 element ?lyric-sequence)))))
1143 (if (string=? ?id ?associated-id)
1144 (format #f "~a~a \\addlyrics ~a"
1145 (music->lily-string ?note-sequence)
1146 (new-line->lily-string)
1147 (parameterize ((*explicit-mode* #f)
1148 (*omit-duration* #t))
1149 (music->lily-string ?lyric-sequence)))
1152 ;; Silence internal event sent at end of each lyrics block
1153 (define-display-method CompletizeExtenderEvent (expr parser)