Hello list, ly2video generates a horizontal scrolling video from one large png. I am trying to modify ly2video to produce a different kind of video that looks like this:
https://www.youtube.com/watch?v=Jb5qj6rQv14 It involves multiple 'snippets' of sheet music that are all the same width. To get there I used a custom paper size: #(set! paper-alist (cons '("vid-line" . (cons (* 90 mm) (* 26 mm))) paper-alist)) \paper { #(set-paper-size "vid-line") } When I run lilypond to output pngs, I get nicely formatted music snippets in multiple pngs. I can then scale them to the video width using python to create pngs and eventually a video. On a side note it would be nicer to specify the resolution of the image I need (so I don't have to scale), but these options: #(ly:set-option 'png-width 1920) #(ly:set-option 'png-height 300) Don't seem to work. The main issues I have relate to the page numbers. The first issue is that lilypond produces files like: video-page1.png and video-page10.png. This requires a natural sorting algorithm that's not built into python. It can be done, but if lilypond could take a format specifier that was 3 digits long to produce video-page001.png, it would make things easier. The second issue is that the space-time-dumper in ly2video produces what I need, but there are no page transitions indicated. I can probably work out the transitions from when the x coordinate wraps, but it would be nice to have the page change show up in the spacetime info output. Ideally with the page number. I put together a rather complicated mwe for anyone able to help. It's two files. I kept the spacetime dumper code in a separate file. The output will be noisy. On linux you can run it like this: lilypond --png mwe.ly | grep ly2video > spacetime.txt to dump the spacetime info to a file. Thanks, Stef
\include "dump-spacetime-info.ly" #(define drumtable '( (bassdrum () #f -3) (snare () #f 1) (hihat cross #f 5) )) drumMusic = \drummode { << { hh8[ hh] <hh sn>[ hh] hh[ hh] <hh sn>[ hh] } \\ { bd4 s4 bd4 s4 } >> } theMusic = \new DrumStaff { \set DrumStaff.drumStyleTable = #(alist->hash-table drumtable) % TODO: figure out how to relocate tempo mark so that it doesn't % impact the vertical height of staves. % \tempo 4 = 100 \repeat unfold 40 \drumMusic } \score { \unfoldRepeats { \theMusic } \layout { \context { \Score \omit BarNumber % make only the first clef visible \override Clef #'break-visibility = #'#(#f #f #f) % make only the first time signature visible \override KeySignature #'break-visibility = #'#(#f #f #f) } } \midi { } } #(set! paper-alist (cons '("vid-line" . (cons (* 90 mm) (* 26 mm))) paper-alist)) \paper { #(set-paper-size "vid-line") print-page-number = ##f % remove indentation indent = 0.0 short-indent = 0.0 % This hack tries to keep the staves in the same vertical place % otherwise the vertical position flucuates due to the height of the % tallest beam. top-system-spacing.basic-distance = #7 } % is there a better way to unset the entire header block? \header { print-all-headers = ##f title = ##f composer = ##f copyright = ##f tagline = ##f } % increase png resolution #(ly:set-option 'resolution 300) % setting this option doesn't work like the command line option. %#(ly:set-option 'backend 'png) % pngalpha doesn't work. %#(ly:set-option 'pixmap-format "pngalpha") % does not work %#(ly:set-option 'png-width 1920) %#(ly:set-option 'png-height 300) % lilypond --png ../mwe.ly | grep ly2video > spacetime.txt \version "2.20.0"
% Huge thanks to Jan Nieuwenhuizen for helping me with this! #(define (grob-get-ancestor-with-interface grob interface axis) (let ((parent (ly:grob-parent grob axis))) (if (null? parent) #f (if (grob::has-interface parent interface) parent (grob-get-ancestor-with-interface parent interface axis))))) #(define (grob-get-paper-column grob) (grob-get-ancestor-with-interface grob 'paper-column-interface X)) #(define (dump-spacetime-info grob) (let* ((extent (ly:grob-extent grob grob X)) (system (ly:grob-system grob)) (x-extent (ly:grob-extent grob system X)) (left (car x-extent)) (right (cdr x-extent)) (paper-column (grob-get-paper-column grob)) (time (ly:grob-property paper-column 'when 0)) (cause (ly:grob-property grob 'cause)) (origin (ly:event-property cause 'origin)) (location (ly:input-file-line-char-column origin)) (file (list-ref location 0)) (line (list-ref location 1)) (char (list-ref location 2)) (column (list-ref location 3)) (drum-type (ly:event-property cause 'drum-type)) (pitch (if (null? drum-type) (ly:event-property cause 'pitch) (ly:assoc-get drum-type midiDrumPitches))) (midi-pitch (if (ly:pitch? pitch) (+ 0.0 (ly:pitch-tones pitch)) "no pitch"))) (if #f (format #t "\nly2video: # pitch ~a drum-type ~a ~a" pitch drum-type (null? drum-type))) (if (not (equal? (ly:grob-property grob 'transparent) #t)) (format #t "\nly2video: (~23,16f, ~23,16f) pitch ~d:~a:~a @ ~23,16f from ~a:~3d:~d" left right (if (ly:pitch? pitch) (ly:pitch-octave pitch) 0) (if (ly:pitch? pitch) (ly:pitch-notename pitch) "?") (if (ly:pitch? pitch) (ly:pitch-alteration pitch) "?") (+ 0.0 (ly:moment-main time) (* (ly:moment-grace time) (/ 9 40))) file line char)))) #(define (dump-spacetime-info-barline grob) (let* ((extent (ly:grob-extent grob grob X)) (system (ly:grob-system grob)) (x-extent (ly:grob-extent grob system X)) (left (car x-extent)) (right (cdr x-extent)) (paper-column (grob-get-paper-column grob)) (time (ly:grob-property paper-column 'when 0)) (cause (ly:grob-property grob 'cause))) (if (not (equal? (ly:grob-property grob 'transparent) #t)) (format #t "\nly2videoBar: (~23,16f, ~23,16f) @ ~23,16f" left right (+ 0.0 (ly:moment-main time) (* (ly:moment-grace time) (/ 9 40))) )))) \layout { \context { \DrumVoice \override NoteHead.after-line-breaking = #dump-spacetime-info } \context { \DrumStaff \override BarLine.after-line-breaking = #dump-spacetime-info-barline } \context { \Voice \override NoteHead.after-line-breaking = #dump-spacetime-info } \context { \Staff \override BarLine.after-line-breaking = #dump-spacetime-info-barline } \context { \ChordNames \override ChordName.after-line-breaking = #dump-spacetime-info } }