[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: calculation of the total duration of a score
From: |
Thomas Morley |
Subject: |
Re: calculation of the total duration of a score |
Date: |
Thu, 8 Sep 2016 10:02:44 +0200 |
2016-09-08 5:39 GMT+02:00 Paul <address@hidden>:
> On 09/05/2016 05:01 AM, Marc Hohl wrote:
>
>> Has someone else already done something like this? I have no experience
>> in writing scheme engravers, so any hint would be highly appreciated.
>
>
> lilypond-html-live-score does something like this by post-processing an SVG
> with python to add meta data to the grobs in the SVG file:
> https://gitlab.com/sigmate/lilypond-html-live-score/blob/master/make-live-score#L88
>
> I was working on porting part of that to scheme so it could be done
> directly. I've attached my include file. It will currently display the
> total duration to the log. It could be simplified in various ways if it was
> calculating just the total duration and not adding timing info to every
> grob.
>
> It's still a work in progress and only lightly tested.
>
> -Paul
Hi,
I've seen Paul answered already, had no time to look into his code, though.
Below my own approach.
Disadvantage: The duration-indication is bound to the last seen event.
This may result in different positions of the RehearsalMark, which I
prefered over TextScript (but this special problem would happen for
both)
\version "2.19.47"
#(define (get-seconds lst rl)
"Takes a list of kind
'((#<Mom 17> 1/15)
(#<Mom 31/2> 1/30)
(#<Mom 0> 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)
(grobs '())
(tempo-change-evts '()))
(make-engraver
(listeners
((rhythmic-event engraver event)
(set! last-evt (ly:event-property event 'length))
(set! evts (cons (ly:context-current-moment context) evts))
;; TODO creating RehearsalMarks at every rhythmic-event looks like
;; a huge waste. How to do it better?
(set! grobs
(cons
(ly:engraver-make-grob engraver 'RehearsalMark event)
grobs)))
((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)))))
((finalize translator)
(let* (;; add default tempo, if not introduced at score-begin
(tempo-changes
(if (null? tempo-change-evts)
(list (cons (ly:make-moment 0) 1/15))
(if (not
(equal? (ly:make-moment 0)
(car (last tempo-change-evts))))
(append
tempo-change-evts (list (cons (ly:make-moment 0) 1/15)))
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))
(minutes (floor final-duration))
;; Is using floor correct?
(seconds (floor (* (- final-duration minutes ) 60)))
(duration-string
(format #f "Duration: ~a:~2,,,'address@hidden" minutes seconds)))
;; Only keep the last created RehearsalMark, suicide the others
(for-each ly:grob-suicide! (cdr grobs))
(ly:grob-set-property! (first grobs) 'direction DOWN)
(ly:grob-set-property! (first grobs) 'text
;; a little custom-formatting
(markup #:rounded-box #:fontsize -3 duration-string))
(set! evts '())
(set! last-evt #f)
(set! grobs '())
(set! tempo-change-evts '()))))))
\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~ |
c'1
}
voiceII = { \partial 4 cis'4 \repeat unfold 18 cis'1 }
\score {
<<
\voiceI
\voiceII
>>
\layout { }
\midi {}
}
Cheers,
Harm
- calculation of the total duration of a score, Marc Hohl, 2016/09/05
- Re: calculation of the total duration of a score, Federico Bruni, 2016/09/05
- Re: calculation of the total duration of a score, Paul, 2016/09/07
- Re: calculation of the total duration of a score,
Thomas Morley <=
- Re: calculation of the total duration of a score, Marc Hohl, 2016/09/08
- Re: calculation of the total duration of a score, Thomas Morley, 2016/09/09
- Re: calculation of the total duration of a score, Paul, 2016/09/10
- Re: calculation of the total duration of a score, Paul, 2016/09/10
- Re: calculation of the total duration of a score, Thomas Morley, 2016/09/10
- Re: calculation of the total duration of a score, Marc Hohl, 2016/09/11
- Re: calculation of the total duration of a score, David Kastrup, 2016/09/11
- Re: calculation of the total duration of a score, Marc Hohl, 2016/09/11
- Re: calculation of the total duration of a score, Paul, 2016/09/12
Re: calculation of the total duration of a score, Marc Hohl, 2016/09/08