Hi Jan-Peter,

ok, so I played around with your engraver. It does exactly what it needs to do, but somehow I am not able to get everything to work.

I'll try to explain:

Let's say that I have some music:

music = {
 ...stuff...
 \repeat volta 2 { ... more stuff ... }
}

and want it displayed nicely:

\score {
  \new Staff { \music }
}

If I include your engraver here, the calculated time is wrong, because the repeats are not taken into account.

So I go for the midi-block

\score {
  \new Staff { \unfoldRepeats \music }
  \midi {
     \context {
        \Score
        \consists ...your code here ...
     }
   }
}


But it looks like the duration variable is visible within its score only, see the attached compilable example.

How can I obtain the correct duration in combination with a compact score?

Thanks in advance,

Marc
Am 13.09.2016 um 10:24 schrieb Jan-Peter Voigt:
Hi Marc,

you already received some solutions, but I stumbled across this thread
and just want to quickly show my engraver - perhaps it also helps.

It doesn't read repeats right now, but this may be solved with
\unfoldRepeats and the engraver placed in the midi-block.
The duration-markup-command relies on a global variable and a delayed
stencil - this will not work with multiple scores, as only the duration
of the last score will be displayed. But that is manageable, if needed.

HTH
Jan-Peter

Am 05.09.2016 um 11:01 schrieb Marc Hohl:
Hi list,

I have a couple of songs in my latest theatre project. It would be nice
to have something like "duration: 3'22''" at the end of each song.

Doing this by hand is straightforward:I generate a midi file that sounds
accurate and let it play by timidity – but IMHO it would be less tedious
and less error-prone if lilypond were capable of doing these
calculations itself.

Tempo indications and meter changes have to be taken into account, so
this is probably doable with a special engraver only IIUC.

Has someone else already done something like this? I have no experience
in writing scheme engravers, so any hint would be highly appreciated.

Thanks in advance,

Marc

_______________________________________________
lilypond-user mailing list
lilypond-user@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-user



_______________________________________________
lilypond-user mailing list
lilypond-user@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-user


\version "2.19.47"

%%% engraver definitions

% format seconds as min:sec
#(define-public (format-time dur)
   (let* ((minutes (floor (/ dur 60)))
          (seconds (round (- dur (* 60 minutes)) ) ))
     (format "~2'0d:~2'0d" (inexact->exact minutes) (inexact->exact seconds))
     ))

% complete duration of score - set after finalizing
duration = 0

% markup command to display complete time
#(define-markup-command (duration layout props)()
   (let* ((gauge-stencil (interpret-markup layout props "00:00"))
          (x-ext (ly:stencil-extent gauge-stencil X))
          (y-ext (ly:stencil-extent gauge-stencil Y)))
     (ly:make-stencil
      `(delay-stencil-evaluation
        ,(delay (ly:stencil-expr
                 (interpret-markup layout props (format-time duration))
                 )))
        x-ext y-ext)
     ))
     
calc-duration-engraver = 
#(lambda (context)
       (let ((dur 0) ; duration in seconds
             (start (ly:make-moment 0)) ; last calc-time the duration was calculated
             )
         ; function to calculate duration in seconds since last calc-time
         (define (calc-dur)
           (let ((diff (ly:moment-sub (ly:context-now context) start) ) ; moment since last calc-time
                 (tempo (ly:context-property context 'tempoWholesPerMinute (ly:make-moment 60/4)) )) ; current tempo
             (set! start (ly:context-now context)) ; set calc-time
             (set! dur ; add 60*(diff/tempo) to duration
                       ; if tempo is 120 BPM and 120/4 elapsed,
                       ; we have 60 * 120/4 * 4/120 = 60 seconds
                   (+ dur
                     (* 60
                       (exact->inexact (ly:moment-main (ly:moment-div diff tempo)))
                       )))
             dur
             ))
         (make-engraver
          (listeners
           ((tempo-change-event engraver event)
            (calc-dur) ; calculate duration on every tempo-change-event (new tempo will be set after we listened to the event)
            (ly:message "duration: ~A" (format-time dur))
            )
           ) ; listeners
          ((finalize trans)
           (calc-dur) ; last calculation of duration
           (set! duration dur) ; set global duration (for the markup command)
           (ly:message "duration: ~A final" (format-time dur))
           )
          )))

%%% actual music example

music = {
  \tempo 4 = 60
  c'4 c' c' c'
  \repeat volta 2 { d'2 d' | e' e' }
  \tempo 4 = 90
  c'4 c' c' c'
}

%%% scores

\score {
   \new Staff { \unfoldRepeats \music }
   \midi {  
      \context {
         \Score
         \consists \calc-duration-engraver
      }
   }
}

\score {
   \new Staff {
      \music
      \mark \markup { \box \duration }
      \bar "|."
   }
}

_______________________________________________
lilypond-user mailing list
lilypond-user@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-user

Reply via email to