Hi Marc,

Well, looks like I sent the file too soon before testing it for this use case. It looks like the html-live-score is using different units of time somehow? I haven't had a chance to look into it or figure out the difference.

Anyway, the attached file will report the correct total duration, thanks to some help from looking at Harm's code. (But I think this version will probably not work with the code for html-live-score...)

Anyway, you're probably better off using Harm's code since it was written for calculating the total duration.

Cheers,
-Paul



On 09/08/2016 06:10 AM, Marc Hohl wrote:
Hi Paul,

thanks for the file. It lookes quite promising, but a quick test shows some strange numbers I do not understand:

test.ly ---

\version "2.19.47"

\include "grob-meta-data-engraver.ily"

\score {
  \new Staff {
     \tempo 4 = 60
     \repeat unfold 60 c'4
   }
   \layout { }
   \midi { }
 }

Processing this file yields to:

GNU LilyPond 2.19.48
»test.ly« wird verarbeitet
Analysieren...
Interpretation der Musik...[8][16][16]3.75
Vorverarbeitung der grafischen Elemente...
Interpretation der Musik...
MIDI-Ausgabe nach »test.midi«...
Ideale Seitenanzahl wird gefunden...
Musik wird auf eine Seite angepasst...
Systeme erstellen...
Layout nach »/tmp/lilypond-pgKSZe« ausgeben...
Konvertierung nach »test.pdf«...
Löschen von »/tmp/lilypond-pgKSZe«...
Kompilation erfolgreich beendet

marc@olivia ~/engraver$ timidity test.midi
Playing test.midi
MIDI file: test.midi
Format: 1  Tracks: 2  Divisions: 384
Sequence:
Text: creator:
Text: GNU LilyPond 2.19.48
Playing time: ~64 seconds
Notes cut: 0
Notes lost totally: 0

It shows a duration of 3.75 in line 4.

A timidity call plays the file in about 64 seconds
(even strange, 60 notes with tempo 4 = 60 should have a total duration of 60 seconds).

What does 3.75 mean?

Marc


Am 08.09.2016 um 05:39 schrieb Paul:
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



_______________________________________________
lilypond-user mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/lilypond-user



_______________________________________________
lilypond-user mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/lilypond-user

\version "2.19.42"

#(define Grob_meta_data_engraver
   (lambda (context)

     (define (get-tempo-change metronome-mark-grob)
       "Returns a pair (moment-fraction . new-tempo-rate) or #f."
       (let*
        ((grob-cause (ly:grob-property metronome-mark-grob 'cause))
         (metronome-count (ly:event-property grob-cause 'metronome-count))
         (tempo-unit (ly:event-property grob-cause 'tempo-unit))
         (moment (grob::when metronome-mark-grob)))
        (if (and metronome-count tempo-unit)
            (cons
             (ly:moment-main moment)
             ;; calculate the new tempo rate
             (/ (string->number
                 (ly:duration->string tempo-unit))
               metronome-count))
            #f)))


     (define (recurse prev-moment prev-time prev-rate grobs tempo-changes)
       "Recursive function to calculate and set timing data for grobs.
        Calculates the actual timing of grobs, honoring tempo changes.
        Returns the total time for the score."
       (let* ((grob (car grobs))
              (moment (ly:moment-main (grob::when grob)))
              (rate-change (if (pair? tempo-changes)
                               (> moment (caar tempo-changes))
                               #f))
              (rate (if rate-change
                        (cdr (car tempo-changes))
                        prev-rate))
              (time (if (= moment prev-moment)
                        prev-time
                        (+ prev-time (* rate (- moment prev-moment)))))
              (id-string (string-append
                          (ly:format "class:ly grob ~a" (grob::name grob))
                          (ly:format ";data-moment:~a" (exact->inexact moment))
                          (ly:format ";data-measure:~a" (car 
(grob::rhythmic-location grob)))
                          (ly:format ";data-real-time:~a" time)
                          )))

         ;; (display id-string)(newline)
         (ly:grob-set-property! grob 'id id-string)

         ;; recurse or return total time if we are done
         (if (null? (cdr grobs))
             time
             (recurse moment time rate (cdr grobs) (if rate-change
                                                       (cdr tempo-changes)
                                                       tempo-changes)))))


     ;; an engraver with a closure
     (let ((grobs '())
           (metronome-mark-grobs '()))
       (make-engraver

        ;; acknowledgers collect grobs
        (acknowledgers
         ((grob-interface engraver grob source-engraver)
          (set! grobs (cons grob grobs)))

         ((metronome-mark-interface engraver grob source-engraver)
          (set! metronome-mark-grobs (cons grob metronome-mark-grobs))))

        ;; finalize stage, calculate and store data on grobs
        ((finalize translator)
         (let*
          ((tempo-changes (filter pair? (map get-tempo-change 
metronome-mark-grobs)))

           (tempo-changes-sorted (sort-list! tempo-changes
                                   (lambda (a b) (< (car a) (car b)))))

           (grobs-sorted (sort-list! (filter grob::name grobs)
                           (lambda (a b)
                             (ly:moment<? (grob::when a) (grob::when b)))))
           ;; initial tempo rate (1/15) is (4 tempo-unit / 60 metronome-count)
           (total-time (recurse 0 0 1/15 grobs-sorted tempo-changes-sorted))

           (minutes (floor total-time))
           ;; Is using floor correct?
           (seconds (floor (* (- total-time minutes ) 60)))
           (duration-string
            (format #f "Total duration: ~a:~2,,,'0@a" minutes seconds))

           (note-head-grobs
            (filter (lambda (grob) (grob::has-interface grob 
'note-head-interface))
                    grobs)))

          (display duration-string)

          ;; add additional data for MetronomeMark grobs
          (for-each (lambda (metronome-mark-grob)
                      (let* ((grob-cause (ly:grob-property metronome-mark-grob 
'cause))
                             (text-prop (ly:event-property grob-cause 'text))
                             (text-string (if (not (null? text-prop))
                                              (ly:format ";data-text:~a" 
text-prop)
                                              ""))
                             (id-string (ly:grob-property metronome-mark-grob 
'id)))
                        (ly:grob-set-property! metronome-mark-grob 'id
                          (string-append id-string text-string))))
            metronome-mark-grobs)

          ;; add additional data for NoteHead grobs
          (for-each (lambda (note-head-grob)
                      (let* ((grob-cause (ly:grob-property note-head-grob 
'cause))
                             (pitch-prop (ly:event-property grob-cause 'pitch))
                             (pitch-string (if (ly:pitch? pitch-prop)
                                               (ly:format ";data-pitch:~a"
                                                 (ly:pitch-semitones 
pitch-prop))
                                               ""))
                             (id-string (ly:grob-property note-head-grob 'id)))
                        
                        ;; (display pitch-string)(newline)
                        
                        (ly:grob-set-property! note-head-grob 'id
                          (string-append id-string pitch-string))))
            note-head-grobs)
          ))))))


\layout {
  \context {
    \Score
    \consists \Grob_meta_data_engraver
  }
}
_______________________________________________
lilypond-user mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/lilypond-user

Reply via email to