\version "2.19.47" printScoreDuration = { \once \override Score.RehearsalMark.direction = #DOWN \once \override Score.RehearsalMark.self-alignment-X = #RIGHT \mark "print-score-duration" } formatScoreDuration = #(define-scheme-function (dur)(exact?) "Returns the given duration as a formated markup containing minutes and seconds." (let* ((minutes (floor dur)) ;; Is using floor correct? (seconds (floor (* (- dur minutes ) 60))) (duration-string (format #f "Duration: ~a:~2,,,'address@hidden" minutes seconds))) #{ \markup \rounded-box \fontsize #-3 #duration-string #})) #(define (get-seconds lst rl) "Takes a list of kind '((# 1/15) (# 1/30) (# 1/15)) Calculates the time passed between each moment. Returns the addition of it as an exact numerical value. " (if (null? (cdr lst)) (apply + rl) (get-seconds (cdr lst) (cons (* (cdr (cadr lst)) (ly:moment-main (ly:moment-sub (caar lst) (caadr lst)))) rl)))) #(define (score-duration-engraver context) (let* ((evts '()) (last-evt #f) (tempo-change-evts '()) (duration-marks '())) (make-engraver (listeners ((rhythmic-event engraver event) (set! last-evt (ly:event-property event 'length)) (set! evts (cons (ly:context-current-moment context) evts))) ((tempo-change-event engraver event) (let ((tempo-unit ;; Hmm, ugly code... (string->number (ly:duration->string (ly:event-property event 'tempo-unit)))) (metronome-count (ly:event-property event 'metronome-count))) ;; Accumulate pairs of "moment when it happens" and ;; "quotient of tempo-unit and metronome-count"in `tempo-change-evts' ;; for use in `get-seconds' (set! tempo-change-evts (cons (cons (ly:context-current-moment context) (/ tempo-unit metronome-count)) tempo-change-evts))))) (acknowledgers ((mark-interface engraver grob source-engraver) (let ((mark-text (ly:grob-property grob 'text))) (if (and (string? mark-text) (string=? mark-text "print-score-duration")) (set! duration-marks (cons grob duration-marks)))))) ((finalize translator) (if duration-marks (let* (;; default tempo, could this be grapped somewhere? (default-tempo-setting (cons (ly:make-moment 0) 1/15)) ; add default tempo, if not introduced at score-begin (tempo-changes (if (or (null? tempo-change-evts) (not (equal? (last tempo-change-evts) default-tempo-setting))) (append tempo-change-evts (list default-tempo-setting)) tempo-change-evts)) (duration-before-last-tempo-change (get-seconds tempo-changes '())) (duration-after-last-tempo-change-without-last-dur (* (cdr (car tempo-changes)) (ly:moment-main (ly:moment-sub (car evts) (caar tempo-changes))))) (last-ev-duration (* (cdar tempo-changes) (ly:moment-main last-evt))) (final-duration (+ duration-before-last-tempo-change duration-after-last-tempo-change-without-last-dur last-ev-duration))) (for-each (lambda (g) (ly:grob-set-property! g 'text (formatScoreDuration final-duration))) duration-marks) (set! evts '()) (set! last-evt #f) (set! tempo-change-evts '()) (set! duration-marks '()))))))) \layout { \context { \Score \consists \score-duration-engraver } } %%%%%%%%%%%%%%%%%%%%%% %% EXAMPLE %%%%%%%%%%%%%%%%%%%%%% voiceI = \new Voice { \partial 4 c'4 \repeat unfold 61 c'4 \tempo 4=120 c'2. d'2 \tempo 8=120 c'2~ | \tuplet 3/2 { c'2 2 2 } } voiceII = { \partial 4 cis'4 \printScoreDuration \repeat unfold 17 cis'1 %% fiddling with two simultaneous RehearsalMarks... cis'1*31/32 \printScoreDuration s1*1/32 \mark \default } \score { << \voiceI \voiceII >> \layout { } \midi {} }