]> git.donarmstrong.com Git - lilypond.git/blobdiff - scm/define-music-display-methods.scm
Issue 2695: Bad output in display-lily-tests.ly
[lilypond.git] / scm / define-music-display-methods.scm
index a620150338b94c55db2305dee06561ea5859508c..9505c3e2b052c50d7e091f0a467f469f5bc5161a 100644 (file)
@@ -1,7 +1,7 @@
 ;;; define-music-display-methods.scm -- data for displaying music
 ;;; expressions using LilyPond notation.
 ;;;
-;;; (c) 2005--2009 Nicolas Sceaux  <nicolas.sceaux@free.fr>
+;;; Copyright (C) 2005--2012 Nicolas Sceaux  <nicolas.sceaux@free.fr>
 ;;;
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -16,7 +16,8 @@
 ;;;
 (define (scheme-expr->lily-string scm-arg)
   (cond ((or (number? scm-arg)
-            (string? scm-arg))
+             (string? scm-arg)
+             (boolean? scm-arg))
         (format #f "~s" scm-arg))
        ((or (symbol? scm-arg)
             (list? scm-arg))
@@ -37,7 +38,8 @@
 ;;;
 
 (define-public (markup->lily-string markup-expr)
-  "Return a string describing, in LilyPond syntax, the given markup expression."
+  "Return a string describing, in LilyPond syntax, the given markup
+expression."
   (define (proc->command proc)
     (let ((cmd-markup (symbol->string (procedure-name proc))))
       (substring cmd-markup 0 (- (string-length cmd-markup)
 (define*-public (duration->lily-string ly-duration #:key (prev-duration (*previous-duration*))
                        (force-duration (*force-duration*))
                        (time-factor-numerator (*time-factor-numerator*))
-                       (time-factor-denominator (*time-factor-denominator*)))
+                       (time-factor-denominator (*time-factor-denominator*))
+                       remember)
+  (if remember (*previous-duration* ly-duration))
   (let ((log2   (ly:duration-log ly-duration))
        (dots    (ly:duration-dot-count ly-duration))
        (num+den (ly:duration-factor ly-duration)))
 ;;; post events
 ;;;
 
-(define post-event?
-  (make-music-type-predicate
-    'AbsoluteDynamicEvent
-    'ArpeggioEvent
-    'ArticulationEvent
-    'BeamEvent
-    'BeamForbidEvent
-    'CrescendoEvent
-    'DecrescendoEvent
-    'ExtenderEvent
-    'FingeringEvent
-    'GlissandoEvent
-    'HarmonicEvent
-    'HyphenEvent
-    'MultiMeasureTextEvent
-    'NoteGroupingEvent
-    'PhrasingSlurEvent
-    'SlurEvent
-    'SostenutoEvent
-    'StringNumberEvent
-    'SustainEvent
-    'TextScriptEvent
-    'TextSpanEvent
-    'TieEvent
-    'TremoloEvent
-    'TrillSpanEvent
-    'TupletSpanEvent
-    'UnaCordaEvent))
+(define (post-event? m)
+  (music-is-of-type? m 'post-event))
 
 (define* (event-direction->lily-string event #:optional (required #t))
   (let ((direction (ly:music-property event 'direction)))
                         ""
                         tremolo-type))))
 
-(define-post-event-display-method ArticulationEvent (event parser) #t
-  (let ((articulation  (ly:music-property event 'articulation-type)))
-    (case (string->symbol articulation)
-      ((marcato) "^")
-      ((stopped) "+")
-      ((tenuto)         "-")
-      ((staccatissimo) "|")
-      ((accent) ">")
-      ((staccato) ".")
-      ((portato) "_")
-      (else (format #f "\\~a" articulation)))))
+(define-display-method ArticulationEvent (event parser) #t
+  (let* ((articulation  (ly:music-property event 'articulation-type))
+        (shorthand
+         (case (string->symbol articulation)
+           ((marcato) "^")
+           ((stopped) "+")
+           ((tenuto)    "-")
+           ((staccatissimo) "|")
+           ((accent) ">")
+           ((staccato) ".")
+           ((portato) "_")
+           (else #f))))
+    (format #f "~a~:[\\~;~]~a"
+           (event-direction->lily-string event shorthand)
+           shorthand
+           (or shorthand articulation))))
 
 (define-post-event-display-method FingeringEvent (event parser) #t
   (ly:music-property event 'digit))
 (define-post-event-display-method MultiMeasureTextEvent (event parser) #t
   (markup->lily-string (ly:music-property event 'text)))
 
+(define-post-event-display-method BendAfterEvent (event parser) #f
+  (format #f "\\bendAfter #~a" (ly:music-property event 'delta-step)))
+
 (define-post-event-display-method HarmonicEvent (event parser) #f "\\harmonic")
-(define-post-event-display-method GlissandoEvent (event parser) #t "\\glissando")
-(define-post-event-display-method ArpeggioEvent (event parser) #t "\\arpeggio")
+(define-post-event-display-method GlissandoEvent (event parser) #f "\\glissando")
+(define-post-event-display-method ArpeggioEvent (event parser) #f "\\arpeggio")
 (define-post-event-display-method AbsoluteDynamicEvent (event parser) #f
   (format #f "\\~a" (ly:music-property event 'text)))
 
+(define-post-event-display-method StrokeFingerEvent (event parser) #f
+  (format #f "\\rightHandFinger #~a" (ly:music-property event 'digit)))
+
 (define-span-event-display-method BeamEvent (event parser) #f "[" "]")
 (define-span-event-display-method SlurEvent (event parser) #f "(" ")")
 (define-span-event-display-method CrescendoEvent (event parser) #f "\\<" "\\!")
 (define-span-event-display-method DecrescendoEvent (event parser) #f "\\>" "\\!")
+(define-span-event-display-method EpisemaEvent (event parser) #f "\\episemInitium" "\\episemFinis")
 (define-span-event-display-method PhrasingSlurEvent (event parser) #f "\\(" "\\)")
 (define-span-event-display-method SustainEvent (event parser) #f "\\sustainOn" "\\sustainOff")
 (define-span-event-display-method SostenutoEvent (event parser) #f "\\sostenutoOn" "\\sostenutoOff")
                                    'SequentialMusic
                                    elements ((music
                                               'EventChord
-                                              elements ((music
-                                                         'SkipEvent
-                                                         duration (ly:make-duration 0 0 0 1))
-                                                        (music
-                                                         'SlurEvent
-                                                         span-direction START))))))
-                          #t)
-         (with-music-match (?stop (music
-                                   'SequentialMusic
-                                   elements ((music
-                                              'EventChord
-                                              elements ((music
-                                                         'SkipEvent
-                                                         duration (ly:make-duration 0 0 0 1))
-                                                        (music
-                                                         'SlurEvent
-                                                         span-direction STOP))))))
+                                              elements
+                                              ((music
+                                                'SlurEvent
+                                                span-direction START))))))
+           #t)
+        (with-music-match (?stop (music
+                                  'SequentialMusic
+                                  elements ((music
+                                             'EventChord
+                                             elements
+                                             ((music
+                                               'SlurEvent
+                                               span-direction STOP))))))
            (format #f "\\appoggiatura ~a" (music->lily-string ?music parser))))))
 
 
                                    'SequentialMusic
                                    elements ((music
                                               'EventChord
-                                              elements ((music
-                                                         'SkipEvent
-                                                         duration (ly:make-duration 0 0 0 1))
-                                                        (music
-                                                         'SlurEvent
-                                                         span-direction START)))
+                                              elements
+                                              ((music
+                                                'SlurEvent
+                                                span-direction START)))
                                              (music
                                               'ContextSpeccedMusic
                                               element (music
                                                        'OverrideProperty
                                                        grob-property-path '(stroke-style)
                                                        grob-value "grace"
-                                                       symbol 'Stem)))))
-                          #t)
+                                                       symbol 'Flag)))))
+          #t)
         (with-music-match (?stop (music
                                   'SequentialMusic
                                   elements ((music
                                              element (music
                                                       'RevertProperty
                                                       grob-property-path '(stroke-style)
-                                                      symbol 'Stem))
+                                                      symbol 'Flag))
+
                                             (music
                                              'EventChord
-                                             elements ((music
-                                                        'SkipEvent
-                                                        duration (ly:make-duration 0 0 0 1))
-                                                       (music
-                                                        'SlurEvent
-                                                        span-direction STOP))))))
+                                             elements
+                                             ((music
+                                               'SlurEvent
+                                               span-direction STOP))))))
           (format #f "\\acciaccatura ~a" (music->lily-string ?music parser))))))
 
 (define-extra-display-method GraceMusic (expr parser)
                                  (*max-element-number-before-break*))))
        (elements (ly:music-property seq 'elements))
        (chord? (make-music-type-predicate 'EventChord))
+       (note-or-chord? (make-music-type-predicate 'EventChord 'NoteEvent
+                                                  'LyricEvent 'RestEvent
+                                                  'ClusterNoteEvent))
        (cluster? (make-music-type-predicate 'ClusterNoteEvent))
        (note? (make-music-type-predicate 'NoteEvent)))
-    (format #f "~a~a{~v%~v_~{~a ~}~v%~v_}"
+    (format #f "~a~a{~v%~v_~{~a~^ ~}~v%~v_}"
            (if (any (lambda (e)
-                      (and (chord? e)
-                           (any cluster? (ly:music-property e 'elements))))
+                      (or (cluster? e)
+                          (and (chord? e)
+                               (any cluster? (ly:music-property e 'elements)))))
                     elements)
                "\\makeClusters "
                "")
                       "\\figuremode ")
                      ((any (lambda (chord)
                              (any (make-music-type-predicate 'LyricEvent)
-                                  (ly:music-property chord 'elements)))
-                           (filter chord? elements))
+                                  (cons chord
+                                        (ly:music-property chord 'elements))))
+                           (filter note-or-chord? elements))
                       "\\lyricmode ")
                      ((any (lambda (chord)
                              (any (lambda (event)
                                     (and (note? event)
                                          (not (null? (ly:music-property event 'drum-type)))))
-                                  (ly:music-property chord 'elements)))
-                           (filter chord? elements))
+                                  (cons chord
+                                        (ly:music-property chord 'elements))))
+                           (filter note-or-chord? elements))
                       "\\drummode ")
                      (else ;; TODO: other modes?
                       ""))
                                          (music->lily-string music parser))
                                        elements))
            (if force-line-break 1 0)
-           (if force-line-break (*indent*) 0))))
+           (if force-line-break (*indent*) 1))))
 
 (define-display-method SimultaneousMusic (sim parser)
   (parameterize ((*indent* (+ 3 (*indent*))))
@@ -431,87 +420,82 @@ Otherwise, return #f."
 ;;;
 
 (define-display-method EventChord (chord parser)
-  ;; event_chord : simple_element post_events
-  ;;              | command_element
+  ;; event_chord : command_element
   ;;              | note_chord_element
 
   ;; TODO : tagged post_events
   ;; post_events : ( post_event | tagged_post_event )*
   ;; tagged_post_event: '-' \tag embedded_scm post_event
 
-  (let* ((elements (ly:music-property chord 'elements))
-        (simple-elements (filter (make-music-type-predicate
-                                  'NoteEvent 'ClusterNoteEvent 'RestEvent
-                                  'MultiMeasureRestEvent 'SkipEvent 'LyricEvent)
-                                 elements)))
-    (if ((make-music-type-predicate 'StaffSpanEvent 'BreathingEvent) (car elements))
-       ;; first, a special case: StaffSpanEvent (\startStaff, \stopStaff)
-       ;; and BreathingEvent (\breathe)
-       (music->lily-string (car elements) parser)
-       (if (and (not (null? simple-elements))
-                (null? (cdr simple-elements))
-                ;; special case: if this simple_element has a HarmonicEvent in its
-                ;; 'articulations list, it should be interpreted instead as a
-                ;; note_chord_element, since \harmonic only works inside chords,
-                ;; even for single notes, e.g., < c\harmonic >
-                (null? (filter (make-music-type-predicate 'HarmonicEvent)
-                               (ly:music-property (car simple-elements) 'articulations))))
-           ;; simple_element : note | figure | rest | mmrest | lyric_element | skip
-           (let* ((simple-element (car simple-elements))
-                  (duration (ly:music-property simple-element 'duration))
-                  (lily-string (format #f "~a~a~a~{~a ~}"
-                                       (music->lily-string simple-element parser)
-                                       (duration->lily-string duration)
-                                       (if (and ((make-music-type-predicate 'RestEvent) simple-element)
-                                                (ly:pitch? (ly:music-property simple-element 'pitch)))
-                                           "\\rest"
-                                           "")
-                                       (map-in-order (lambda (music)
-                                                       (music->lily-string music parser))
-                                                     (filter post-event? elements)))))
-             (*previous-duration* duration)
-             lily-string)
-           (let ((chord-elements (filter (make-music-type-predicate
-                                          'NoteEvent 'ClusterNoteEvent 'BassFigureEvent)
-                                         elements))
-                 (post-events (filter post-event? elements)))
-             (if (not (null? chord-elements))
-                 ;; note_chord_element : '<' (notepitch | drumpitch)* '>" duration post_events
-                 (let ((lily-string (format #f "< ~{~a ~}>~a~{~a ~}"
-                                            (map-in-order (lambda (music)
-                                                            (music->lily-string music parser))
-                                                          chord-elements)
-                                            (duration->lily-string (ly:music-property (car chord-elements)
-                                                                                      'duration))
-                                            (map-in-order (lambda (music)
-                                                            (music->lily-string music parser))
-                                                          post-events))))
-                   (*previous-duration* (ly:music-property (car chord-elements) 'duration))
-                   lily-string)
-                 ;; command_element
-                 (format #f "~{~a ~}" (map-in-order (lambda (music)
-                                                      (music->lily-string music parser))
-                                                    elements))))))))
+  (let* ((elements (append (ly:music-property chord 'elements)
+                          (ly:music-property chord 'articulations)))
+        (chord-repeat (ly:music-property chord 'duration)))
+    (call-with-values
+       (lambda ()
+         (partition (lambda (m) (music-is-of-type? m 'rhythmic-event))
+                    elements))
+      (lambda (chord-elements other-elements)
+       (cond ((pair? chord-elements)
+              ;; note_chord_element :
+              ;; '<' (notepitch | drumpitch)* '>" duration post_events
+              (let ((duration (duration->lily-string (ly:music-property
+                                                      (car chord-elements)
+                                                      'duration)
+                                                     #:remember #t)))
+                ;; Format duration first so that it does not appear on
+                ;; chord elements
+                (format #f "< ~{~a ~}>~a~:{~:[-~;~]~a~^ ~}"
+                        (map-in-order (lambda (music)
+                                        (music->lily-string music parser))
+                                      chord-elements)
+                        duration
+                        (map-in-order (lambda (music)
+                                        (list
+                                         (post-event? music)
+                                         (music->lily-string music parser)))
+                                      other-elements))))
+             ((ly:duration? chord-repeat)
+              (let ((duration (duration->lily-string chord-repeat
+                                                     #:remember #t)))
+                (format #f "q~a~:{~:[-~;~]~a~^ ~}"
+                        duration
+                        (map-in-order (lambda (music)
+                                        (list
+                                         (post-event? music)
+                                         (music->lily-string music parser)))
+                                      other-elements))))
+
+             ((and (= 1 (length other-elements))
+                   (not (post-event? (car other-elements))))
+              (format #f (music->lily-string (car other-elements) parser)))
+             (else
+              (format #f "< >~:{~:[-~;~]~a~^ ~}"
+                      (map-in-order (lambda (music)
+                                      (list
+                                       (post-event? music)
+                                       (music->lily-string music parser)))
+                                    other-elements))))))))
 
 (define-display-method MultiMeasureRestMusic (mmrest parser)
-  (let* ((dur (ly:music-property mmrest 'duration))
-        (ly (format #f "R~a~{~a ~}"
-                    (duration->lily-string dur)
-                    (map-in-order (lambda (music)
-                                    (music->lily-string music parser))
-                                  (ly:music-property mmrest 'articulations)))))
-    (*previous-duration* dur)
-    ly))
+  (format #f "R~a~{~a~^ ~}"
+         (duration->lily-string (ly:music-property mmrest 'duration)
+                                #:remember #t)
+         (map-in-order (lambda (music)
+                         (music->lily-string music parser))
+                       (ly:music-property mmrest 'articulations))))
 
 (define-display-method SkipMusic (skip parser)
   (format #f "\\skip ~a" (duration->lily-string (ly:music-property skip 'duration) #:force-duration #t)))
 
+(define-display-method OttavaMusic (ottava parser)
+  (format #f "\\ottava #~a" (ly:music-property ottava 'ottava-number)))
+
 ;;;
 ;;; Notes, rests, skips...
 ;;;
 
 (define (simple-note->lily-string event parser)
-  (format #f "~a~a~a~a~{~a~}" ; pitchname octave !? octave-check articulations
+  (format #f "~a~a~a~a~a~a~:{~:[-~;~]~a~}" ; pitchname octave !? octave-check duration optional_rest articulations
          (note-name->lily-string (ly:music-property event 'pitch) parser)
          (octave->lily-string (ly:music-property event 'pitch))
          (let ((forced (ly:music-property event 'force-accidental))
@@ -531,15 +515,26 @@ Otherwise, return #f."
                                        (make-string (1- (* -1 octave-check)) #\,))
                                       (else "")))
                ""))
+         (duration->lily-string (ly:music-property event 'duration)
+                                #:remember #t)
+         (if ((make-music-type-predicate 'RestEvent) event)
+             "\\rest" "")
          (map-in-order (lambda (event)
-                         (music->lily-string event parser))
+                         (list
+                          (post-event? event)
+                          (music->lily-string event parser)))
                        (ly:music-property event 'articulations))))
 
 (define-display-method NoteEvent (note parser)
   (cond ((not (null? (ly:music-property note 'pitch))) ;; note
         (simple-note->lily-string note parser))
        ((not (null? (ly:music-property note 'drum-type))) ;; drum
-        (format #f "~a" (ly:music-property note 'drum-type)))
+        (format #f "~a~a~{~a~}" (ly:music-property note 'drum-type)
+                (duration->lily-string (ly:music-property note 'duration)
+                                       #:remember #t)
+                (map-in-order (lambda (event)
+                                (music->lily-string event parser))
+                              (ly:music-property note 'articulations))))
        (else ;; unknown?
         "")))
 
@@ -549,13 +544,27 @@ Otherwise, return #f."
 (define-display-method RestEvent (rest parser)
   (if (not (null? (ly:music-property rest 'pitch)))
       (simple-note->lily-string rest parser)
-      "r"))
+      (format #f "r~a~{~a~}"
+             (duration->lily-string (ly:music-property rest 'duration)
+                                    #:remember #t)
+             (map-in-order (lambda (event)
+                             (music->lily-string event parser))
+                           (ly:music-property rest 'articulations)))))
 
 (define-display-method MultiMeasureRestEvent (rest parser)
-  "R")
+  (string-append "R" (duration->lily-string (ly:music-property rest 'duration)
+                                           #:remember #t)))
 
 (define-display-method SkipEvent (rest parser)
-  "s")
+  (format #f "s~a~{~a~}"
+         (duration->lily-string (ly:music-property rest 'duration)
+                                #:remember #t)
+         (map-in-order (lambda (event)
+                         (music->lily-string event parser))
+                       (ly:music-property rest 'articulations))))
+
+(define-display-method RepeatedChord (chord parser)
+  (music->lily-string (ly:music-property chord 'element) parser))
 
 (define-display-method MarkEvent (mark parser)
   (let ((label (ly:music-property mark 'label)))
@@ -624,18 +633,21 @@ Otherwise, return #f."
            (if (null? bracket-stop) "" "]"))))
 
 (define-display-method LyricEvent (lyric parser)
-  (let ((text (ly:music-property lyric 'text)))
-    (if (or (string? text)
-           (eqv? (first text) simple-markup))
-       ;; a string or a simple markup
-       (let ((string (if (string? text)
-                         text
-                         (second text))))
-         (if (string-match "(\"| |[0-9])" string)
-             ;; TODO check exactly in which cases double quotes should be used
-             (format #f "~s" string)
-             string))
-       (markup->lily-string text))))
+  (format "~a~{~a~^ ~}"
+         (let ((text (ly:music-property lyric 'text)))
+           (if (or (string? text)
+                   (eqv? (first text) simple-markup))
+               ;; a string or a simple markup
+               (let ((string (if (string? text)
+                                 text
+                                 (second text))))
+                 (if (string-match "(\"| |[0-9])" string)
+                     ;; TODO check exactly in which cases double quotes should be used
+                     (format #f "~s" string)
+                     string))
+               (markup->lily-string text)))
+         (map-in-order (lambda (m) (music->lily-string m parser))
+                       (ly:music-property lyric 'articulations))))
 
 (define-display-method BreathingEvent (event parser)
   "\\breathe")
@@ -677,18 +689,21 @@ Otherwise, return #f."
 ;;; Repeats
 ;;;
 
+(define-display-method AlternativeEvent (alternative parser) "")
+
 (define (repeat->lily-string expr repeat-type parser)
-  (format #f "\\repeat ~a ~a ~a ~a"
-         repeat-type
-         (ly:music-property expr 'repeat-count)
-         (music->lily-string (ly:music-property expr 'element) parser)
-         (let ((alternatives (ly:music-property expr 'elements)))
-           (if (null? alternatives)
-               ""
-               (format #f "\\alternative { ~{~a ~}}"
-                       (map-in-order (lambda (music)
-                                       (music->lily-string music parser))
-                                     alternatives))))))
+  (let* ((main (music->lily-string (ly:music-property expr 'element) parser)))
+    (format #f "\\repeat ~a ~a ~a ~a"
+           repeat-type
+           (ly:music-property expr 'repeat-count)
+           main
+           (let ((alternatives (ly:music-property expr 'elements)))
+             (if (null? alternatives)
+                 ""
+                 (format #f "\\alternative { ~{~a ~}}"
+                         (map-in-order (lambda (music)
+                                         (music->lily-string music parser))
+                                       alternatives)))))))
 
 (define-display-method VoltaRepeatedMusic (expr parser)
   (repeat->lily-string expr "volta" parser))
@@ -700,35 +715,29 @@ Otherwise, return #f."
   (repeat->lily-string expr "percent" parser))
 
 (define-display-method TremoloRepeatedMusic (expr parser)
-  (let* ((count (ly:music-property expr 'repeat-count))
-        (dots (if (= 0 (modulo count 3)) 0 1))
-        (shift (- (log2 (if (= 0 dots)
-                            (/ (* count 2) 3)
-                            count))))
-        (element (ly:music-property expr 'element))
-        (den-mult 1))
-    (if (eqv? (ly:music-property element 'name) 'SequentialMusic)
-       (begin
-         (set! shift (1- shift))
-         (set! den-mult (length (ly:music-property element 'elements)))))
-    (music-map (lambda (m)
-                (let ((duration (ly:music-property m 'duration)))
-                  (if (ly:duration? duration)
-                      (let* ((dlog (ly:duration-log duration))
-                             (ddots (ly:duration-dot-count duration))
-                             (dfactor (ly:duration-factor duration))
-                             (dnum (car dfactor))
-                             (dden (cdr dfactor)))
-                        (set! (ly:music-property m 'duration)
-                              (ly:make-duration (- dlog shift)
-                                                ddots ;;(- ddots dots) ; ????
-                                                dnum
-                                                (/ dden den-mult))))))
-                m)
-              element)
+  (let* ((main (ly:music-property expr 'element))
+        (children (if (music-is-of-type? main 'sequential-music)
+                      ;; \repeat tremolo n { ... }
+                      (length (extract-named-music main '(EventChord
+                                                          NoteEvent)))
+                      ;; \repeat tremolo n c4
+                      1))
+        (times (ly:music-property expr 'repeat-count))
+
+        ;; # of dots is equal to the 1 in bitwise representation (minus 1)!
+        (dots (1- (logcount (* times children))))
+        ;; The remaining missing multiplicator to scale the notes by
+        ;; times * children
+        (mult (/ (* times children (ash 1 dots)) (1- (ash 2 dots))))
+        (shift (- (ly:intlog2 (floor mult)))))
+    (set! main (ly:music-deep-copy main))
+    ;; Adjust the time of the notes
+    (ly:music-compress main (ly:make-moment children 1))
+    ;; Adjust the displayed note durations
+    (shift-duration-log main (- shift) (- dots))
     (format #f "\\repeat tremolo ~a ~a"
-           count
-           (music->lily-string element parser))))
+           times
+           (music->lily-string main parser))))
 
 ;;;
 ;;; Contexts
@@ -757,7 +766,7 @@ Otherwise, return #f."
                                         (*indent*)
                                         (first op)
                                         (second op)))
-                              (reverse operations)))
+                              operations))
                        (*indent*)))
            (parameterize ((*current-context* ctype))
              (music->lily-string music parser)))))
@@ -836,10 +845,8 @@ Otherwise, return #f."
 
 (define-display-method OverrideProperty (expr parser)
   (let* ((symbol         (ly:music-property expr 'symbol))
-        (property-path   (ly:music-property expr 'grob-property-path))
-        (properties      (if (pair? property-path)
-                             property-path
-                             (list (ly:music-property expr 'grob-property))))
+        (properties   (ly:music-property expr 'grob-property-path
+                                             (list (ly:music-property expr 'grob-property))))
         (value   (ly:music-property expr 'grob-value))
         (once    (ly:music-property expr 'once)))
 
@@ -859,8 +866,9 @@ Otherwise, return #f."
            (new-line->lily-string))))
 
 (define-display-method RevertProperty (expr parser)
-  (let ((symbol (ly:music-property expr 'symbol))
-       (properties (ly:music-property expr 'grob-property-path)))
+  (let* ((symbol (ly:music-property expr 'symbol))
+         (properties (ly:music-property expr 'grob-property-path
+                                             (list (ly:music-property expr 'grob-property)))))
     (format #f "\\revert ~a~a #'~a~a"
            (if (eqv? (*current-context*) 'Bottom)
                ""
@@ -871,6 +879,20 @@ Otherwise, return #f."
                properties)
            (new-line->lily-string))))
 
+(define-display-method TimeSignatureMusic (expr parser)
+  (let* ((num (ly:music-property expr 'numerator))
+         (den (ly:music-property expr 'denominator))
+         (structure (ly:music-property expr 'beat-structure)))
+    (if (null? structure)
+        (format #f
+                "\\time ~a/~a~a"
+                num den
+                (new-line->lily-string))
+        (format #f
+                "\\time #'~a ~a/~a~a" 
+                structure num den
+                (new-line->lily-string)))))
+
 ;;; \melisma and \melismaEnd
 (define-extra-display-method ContextSpeccedMusic (expr parser)
   "If expr is a melisma, return \"\\melisma\", otherwise, return #f."
@@ -888,53 +910,35 @@ Otherwise, return #f."
     "\\melismaEnd"))
 
 ;;; \tempo
-;;; Check for all three different syntaxes of tempo:
-;;; \tempo string duration=note, \tempo duration=note and \tempo string
-(define-extra-display-method ContextSpeccedMusic (expr parser)
-  "If expr is a tempo, return \"\\tempo x = nnn\", otherwise return #f."
-  (or   (with-music-match (expr (music 'ContextSpeccedMusic
-               element (music 'SequentialMusic
-                             elements ((music 'PropertySet
-                                         value ?unit-text
-                                         symbol 'tempoText)
-                                       (music 'PropertySet
-                                         symbol 'tempoWholesPerMinute)
-                                       (music 'PropertySet
-                                         value ?unit-duration
-                                         symbol 'tempoUnitDuration)
-                                       (music 'PropertySet
-                                         value ?unit-count
-                                         symbol 'tempoUnitCount)))))
-               (format #f "\\tempo ~a ~a = ~a"
-                       (scheme-expr->lily-string ?unit-text)
-                       (duration->lily-string ?unit-duration #:force-duration #t)
-                       ?unit-count))
-       (with-music-match (expr (music 'ContextSpeccedMusic
-                   element (music 'SequentialMusic
-                             elements ((music 'PropertyUnset
-                                         symbol 'tempoText)
-                                       (music 'PropertySet
-                                         symbol 'tempoWholesPerMinute)
-                                       (music 'PropertySet
-                                         value ?unit-duration
-                                         symbol 'tempoUnitDuration)
-                                       (music 'PropertySet
-                                         value ?unit-count
-                                         symbol 'tempoUnitCount)))))
-                       (format #f "\\tempo ~a = ~a"
-                               (duration->lily-string ?unit-duration #:force-duration #t)
-                               ?unit-count))
-       (with-music-match (expr (music 'ContextSpeccedMusic
-                           element (music 'SequentialMusic
-                                     elements ((music 'PropertySet
-                                                 value ?tempo-text
-                                                symbol 'tempoText)))))
-                       (format #f "\\tempo ~a" (scheme-expr->lily-string ?tempo-text)))))
+(define-extra-display-method SequentialMusic (expr parser)
+  (with-music-match (expr (music 'SequentialMusic
+                                elements ((music 'TempoChangeEvent
+                                                 text ?text
+                                                 tempo-unit ?unit
+                                                 metronome-count ?count)
+                                          (music 'ContextSpeccedMusic
+                                                 element (music 'PropertySet
+                                                                symbol 'tempoWholesPerMinute)))))
+    (format #f "\\tempo ~{~a~a~}~a = ~a~a"
+           (if (markup? ?text)
+               (list (markup->lily-string ?text) " ")
+               '())
+           (duration->lily-string ?unit #:force-duration #t)
+           (if (pair? ?count)
+               (format #f "~a ~~ ~a" (car ?count) (cdr ?count))
+               ?count)
+           (new-line->lily-string))))
+
+(define-display-method TempoChangeEvent (expr parser)
+  (let ((text (ly:music-property expr 'text)))
+    (format #f "\\tempo ~a~a"
+           (markup->lily-string text)
+           (new-line->lily-string))))
 
 ;;; \clef
 (define clef-name-alist #f)
 (define-public (memoize-clef-names clefs)
-  "Initialize `clef-name-alist', if not already set."
+  "Initialize @code{clef-name-alist}, if not already set."
   (if (not clef-name-alist)
       (set! clef-name-alist
             (map (lambda (name+vals)
@@ -943,8 +947,8 @@ Otherwise, return #f."
                  clefs))))
 
 (define-extra-display-method ContextSpeccedMusic (expr parser)
-  "If `expr' is a clef change, return \"\\clef ...\"
-Otherwise, return #f."
+  "If @var{expr} is a clef change, return \"\\clef ...\".
+Otherwise, return @code{#f}."
   (with-music-match (expr (music 'ContextSpeccedMusic
                                 context-type 'Staff
                                 element (music 'SequentialMusic
@@ -962,7 +966,7 @@ Otherwise, return #f."
                                                          (music 'ApplyContext
                                                                 procedure ly:set-middle-C!)))))
     (let ((clef-name (assoc-get (list ?clef-glyph ?clef-position 0)
-                                clef-name-alist)))
+                               clef-name-alist)))
       (if clef-name
          (format #f "\\clef \"~a~{~a~a~}\"~a"
                  clef-name
@@ -975,41 +979,6 @@ Otherwise, return #f."
                  (new-line->lily-string))
          #f))))
 
-;;; \time
-(define-extra-display-method ContextSpeccedMusic (expr parser)
-  "If `expr' is a time signature set, return \"\\time ...\".
-Otherwise, return #f.  Note: default grouping is not available."
-  (with-music-match
-   (expr (music
-           'ContextSpeccedMusic
-          element (music
-                   'ContextSpeccedMusic
-                   context-type 'Timing
-                   element (music
-                            'SequentialMusic
-                            elements ?elts))))
-   (and
-    (> (length ?elts) 2)
-    (with-music-match ((cadr ?elts)
-                       (music 'PropertySet
-                              symbol 'beatLength))
-       #t)
-    (with-music-match ((caddr ?elts)
-                       (music 'PropertySet
-                              symbol 'measureLength))
-       #t)
-    (with-music-match ((car ?elts)
-                       (music 'PropertySet
-                              value ?num+den
-                              symbol 'timeSignatureFraction))
-       (if (eq? (length ?elts) 3)
-           (format
-             #f "\\time ~a/~a~a"
-             (car ?num+den) (cdr ?num+den) (new-line->lily-string))
-           (format
-             #f "#(set-time-signature ~a ~a '(<grouping-specifier>))~a"
-             (car ?num+den) (cdr ?num+den)  (new-line->lily-string)))))))
-
 ;;; \bar
 (define-extra-display-method ContextSpeccedMusic (expr parser)
   "If `expr' is a bar, return \"\\bar ...\".
@@ -1019,33 +988,9 @@ Otherwise, return #f."
                                 element (music 'PropertySet
                                                value ?bar-type
                                                symbol 'whichBar)))
-     (format #f "\\bar \"~a\"~a" ?bar-type (new-line->lily-string))))
+    (format #f "\\bar \"~a\"~a" ?bar-type (new-line->lily-string))))
 
 ;;; \partial
-(define (duration->moment ly-duration)
-  (let ((log2   (ly:duration-log ly-duration))
-       (dots    (ly:duration-dot-count ly-duration))
-       (num+den (ly:duration-factor ly-duration)))
-    (let* ((m (expt 2 (- log2)))
-          (factor (/ (car num+den) (cdr num+den))))
-      (/ (do ((i 0 (1+ i))
-             (delta (/ m 2) (/ delta 2)))
-            ((= i dots) m)
-          (set! m (+ m delta)))
-        factor))))
-
-(define moment-duration-alist (map (lambda (duration)
-                                    (cons (duration->moment duration)
-                                          duration))
-                                  (append-map (lambda (log2)
-                                                (map (lambda (dots)
-                                                       (ly:make-duration log2 dots 1 1))
-                                                     (list 0 1 2 3)))
-                                              (list 0 1 2 3 4))))
-
-(define (moment->duration moment)
-  (assoc-get (- moment) moment-duration-alist))
-
 (define-extra-display-method ContextSpeccedMusic (expr parser)
   "If `expr' is a partial measure, return \"\\partial ...\".
 Otherwise, return #f."
@@ -1055,13 +1000,12 @@ Otherwise, return #f."
                                    'ContextSpeccedMusic
                                    context-type 'Timing
                                    element (music
-                                            'PropertySet
-                                            value ?moment
-                                            symbol 'measurePosition))))
-     (let ((duration (moment->duration (/ (ly:moment-main-numerator ?moment)
-                                         (ly:moment-main-denominator ?moment)))))
-       (and duration (format #f "\\partial ~a" (duration->lily-string duration
-                                                #:force-duration #t))))))
+                                            'PartialSet
+                                            partial-duration ?duration))))
+
+    (and ?duration
+        (format #f "\\partial ~a"
+                (duration->lily-string ?duration #:force-duration #t)))))
 
 ;;;
 ;;;
@@ -1196,4 +1140,6 @@ Otherwise, return #f."
                  (music->lily-string ?lyric-sequence parser)))
        #f)))
 
-
+;; Silence internal event sent at end of each lyrics block
+(define-display-method CompletizeExtenderEvent (expr parser)
+  "")