Am 13.09.2016 um 02:29 schrieb Paul:
Hi Knut,
Sounds cool! I'd like to check it out when I get a chance. I'm curious how it
compares with ly2video?
https://github.com/aspiers/ly2video
Some differences between my script and ly2video.py:
=================================
-> ly2video supports older versions of lilypond, my script needs at least
version 2.19.23
-> ly2video requires clean 7-bit source files, it's almost unusable for vocal
music if the lyrics text
requires characters from european languages that use diacritics (german,
french, ...) or completely
different characters (russian ....). My script does not have this
limitation.
-> ly2video is very slow compared to my script (see below), especially on a
multi-core cpu
-> ly2video files are big, even if you turn off the cursor
-> ly2video uses a single very long system and cuts part from that. This is a
problem if the
number of instruments used is not constant.
-> my script does not generate a cursor as I believe that it is useless --- if
you know how to read
music, you do not need it, if you don't know how to read music it does not
help either.
-> There are some bugs in ly2video that cause it to loose sync sometimes (but
there are probably
bugs in my script / videohelper.ily too)
Some measurements
=============
Test: Converting a lilypond source of J.S. Bach Invention Nr. 1
System: OS: Linux, cpu: i4790K cpu
ly2video, set to generate no cursor and identical Y-resolution
======================================
Processing time: 63.0 +/- 0.5 seconds
size of video file: 10.498.048 bytes
My script with h264 preset "ultrafast"
=======================
Processing time: 6.45 +/- 0.15 seconds (includes lilypond processing time of
1.0 +/- 0.05s)
size of video file: 4.134.850 bytes
My script with h264 preset "veryslow"
=======================
Processing time 12.5 +/- 0.1 seconds (includes lilypond processing time of 1.0
+/- 0.05s)
size of video file: 1.843.136 bytes
Attached find a new version of my script and an example source
========================================
Changes: -> Add metronome ticks at start of music
-> remove temporary files
-> limit number of parallel jobs to (virtual or real) cpu cores
+ 1
-> fix a bug in videohelper.ily
Missing : -> errors are ignored most of the time ...
cu,
Knut
#!/bin/bash
######################################################################
# Copyright (C) 2016 Knut Petersen (knut_peter...@t-online.de)
#
# This is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This file is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
######################################################################
# FPS=n: video files will use n frames per second
FPS=25
# TITLETIME: number of seconds the title page shall be visible
TITLETIME=6.0
# AFTERTIME
AFTERTIME=4.0
# PRESET: x264 preset to be used by ffmpeg for final output
PRESET=veryslow
PRESET=ultrafast
# DEBUG: n != 0 turns on debugging mode (verbose output)
DEBUG=0
# CLEAN: n != 0 enables deletion of all temporary files
CLEAN=1
FAIL=0
function weneedprog {
for P in $@; do
TMP=`which $P 2> /dev/null`
if [ "x" == "x$TMP" ]; then
echo We need $P but could not find it!
FAIL=$((FAIL+1))
fi
done
}
function weneeddata {
for P in $@; do
TMP=`ls -q $P 2> /dev/null`
if [ "x" == "x$TMP" ]; then
echo We need $P but could not find it!
FAIL=$((FAIL+1))
fi
done
}
echo checking dependencies ...
weneedprog ls sort tail uniq grep sed usleep bc gs pdftk lilypond fluidsynth
sox ffmpeg
weneeddata /usr/share/sounds/sf2/FluidR3_GM.sf2 videohelper.notes
if [ $FAIL -ne 0 ]; then
echo $FAIL missing dependencies, aborting
exit 1
else
echo dependencies ok
fi
function checknotes {
grep "$1" videohelper.notes &> /dev/null
if [ $? -ne 0 ]; then
echo Fatal error: $2
exit 2
fi
}
echo checking videohelper.notes ...
checknotes "LILYSOURCE" "LILYSOURCE undefined"
checknotes "VIDEOSOURCE" "VIDEOSOURCE undefined"
checknotes "MIDISOURCE" "MIDISOURCE undefined"
checknotes "tempo" "no tempo definition"
checknotes "note" "not a single note event"
checknotes "page 1 contains no music" "no title page defined"
checknotes "[0-9.]* page" "not a single page"
echo videohelper.notes ok
TDIR=`mktemp -d mkvideo-XXXXX`
eval `grep LILYSOURCE videohelper.notes`
eval `grep VIDEOSOURCE videohelper.notes`
MIDILIST=`grep MIDISOURCE videohelper.notes | sed -e
"s/MIDISOURCE=\([[:print:]]*\).midi/\1/" | sort | uniq | sed ':a;N;$!ba;s/\n/
/g'`
LASTMOMENT=$(echo `sort -n videohelper.notes | grep 'note\|rest' | tail -n 1 | \
sed -e
's/\([0-9.]*\)\([[:space:]]*\)\(note\|rest\)\([[:space:]]*\)\([0-9.]*\)/\1+\5/'`
| bc -l)
MOMENTLIST="`grep "[0-9.]* page" videohelper.notes | sed -e
"s/\([0-9.]*\)[[:space:]][[:print:]]*/\1/" | sed ':a;N;$!ba;s/\n/ /g'`
$LASTMOMENT"
COUNT=1
ARMOM=()
for VAL in $MOMENTLIST; do
ARMOM[COUNT]=$VAL
COUNT=$((COUNT+1))
done
if [ $DEBUG -ne 0 ] ; then
declare -p ARMOM
fi
TEMPOMOMENTLIST=`grep tempo videohelper.notes | sed -e
"s/\([0-9.]*\)[[:space:]]tempo[[:space:]]\([0-9.]*\)/\1 /" | sed
':a;N;$!ba;s/\n/ /g'`
COUNT=1
TMMOM=()
for VAL in $TEMPOMOMENTLIST; do
TMMOM[COUNT]=$VAL
COUNT=$((COUNT+1))
done
TMMOM[COUNT]=100000.0
if [ $DEBUG -ne 0 ] ; then
declare -p TMMOM
fi
TEMPOTIMELIST=`grep tempo videohelper.notes | sed -e
"s/\([0-9.]*\)[[:space:]]tempo[[:space:]]\([0-9.]*\)/\2 /" | sed
':a;N;$!ba;s/\n/ /g'`
COUNT=1
TTMOM=()
for VAL in $TEMPOTIMELIST; do
TTMOM[COUNT]=$VAL
COUNT=$((COUNT+1))
done
TTMOM[COUNT]=0.0
if [ $DEBUG -ne 0 ] ; then
declare -p TTMOM
fi
TEMPOS=`grep tempo videohelper.notes | wc | sed -e
"s/[[:space:]]*\([[:digit:]]*\)[[:print:]]*/\1/"`
if [ $DEBUG -ne 0 ] ; then
echo TEMPOS $TEMPOS
fi
PAGES=`grep page videohelper.notes | wc | sed -e
"s/[[:space:]]*\([[:digit:]]*\)[[:print:]]*/\1/"`
PAGES=$((PAGES-1))
if [ $DEBUG -ne 0 ] ; then
echo PAGES $PAGES
fi
MOMENTS=$((PAGES+1))
if [ $DEBUG -ne 0 ] ; then
echo MOMENTS $MOMENTS
fi
for M in `seq 1 $MOMENTS`;
do ARTIMES[M]=0.0
done
for T in `seq 1 $TEMPOS`; do
for M in `seq 1 $MOMENTS`; do
if (( $(echo "${ARMOM[$M]} > ${TMMOM[$T]}" |bc -l) )); then
if (( $(echo "${ARMOM[$M]} <= ${TMMOM[$((T+1))]}" |bc -l) )); then
ARTIMES[$M]=`bc -l
<<<"${ARTIMES[$M]}+(${ARMOM[$M]}-${TMMOM[$T]})*${TTMOM[$T]}"`
else
ARTIMES[$M]=`bc -l
<<<"${ARTIMES[$M]}+(${TMMOM[$((T+1))]}-${TMMOM[$T]})*${TTMOM[$T]}"`
fi
fi
done
done
for M in `seq 1 $MOMENTS`; do
ARTIMES[$M]=$(echo $(bc <<< "(${ARTIMES[$M]})*$FPS/1")/$FPS | bc -l)
done
if [ $DEBUG -ne 0 ] ; then
echo The first page \(title\) will be visible for "$TITLETIME"s.
echo The last page will be visible for "$AFTERTIME"s after the end of the
last note/rest.
for P in `seq 1 $PAGES`; do
echo "page $((P+1)) from moment ${ARMOM[$P]} to ${ARMOM[$((P+1))]}
(${ARTIMES[$P]}s to ${ARTIMES[$((P+1))]}s)"
done
fi
METROTIME=`grep tempo videohelper.notes | sort -n | head -n 1 | sed -e
"s/[0-9.]*[[:space:]]tempo[[:space:]]//"`
ARVT[1]=$TITLETIME
for M in `seq 1 $PAGES`;
do
ARVT[$((M+1))]=`bc <<<${ARTIMES[$((M+1))]}-${ARTIMES[$M]}`
done
ARVT[$MOMENTS]=`bc <<<${ARVT[$MOMENTS]}+$AFTERTIME`
ARVT[2]=`bc <<<${ARVT[2]}+$METROTIME`
if [ $DEBUG -ne 0 ] ; then
declare -p ARVT
fi
PAGELIST=`grep -o "page [[:digit:]]*" videohelper.notes | sort -n | sed -e
"s/\(page\) \([[:digit:]]*\)/\1\2/" | sed ':a;N;$!ba;s/\n/ /g'`
MAXJOBS=2
if [ -e "/proc/cpuinfo" ]; then
if [ -r "/proc/cpuinfo" ]; then
MAXJOBS=$((`grep processor /proc/cpuinfo | wc | sed -e
"s/[[:space:]]*\([[:digit:]]*\)[[:space:]]*[[:print:]]*/\1/"`+1))
fi
fi
echo we decided to use up to $MAXJOBS parallel jobs ...
function limitjobs {
while [ `jobs | wc | sed -e
"s/[[:space:]]*\([[:digit:]]*\)[[:space:]]*[[:print:]]*/\1/"` -ge $MAXJOBS ]; do
usleep 250
done
}
echo generating metronome ticks ...
FIRSTTEMPO=`echo 60/$METROTIME*4 | bc -l`
FIRSTTEMPO=`echo $FIRSTTEMPO/1 | bc`
echo "\version \"2.19.47\" \score { \drums { wbl4 4 4 4 } \midi { \tempo 4 =
$FIRSTTEMPO } }" > $TDIR/metronome.ly
cd $TDIR
lilypond metronome.ly &> /dev/null &
cd ..
echo generating tsilence.wav ...
sox -n -r 44100 -c 2 -b16 $TDIR/tsilence.wav trim 0.0 $TITLETIME &>
$TDIR/sox-tsilence.log &
echo generating wav files from midi input ...
for M in $MIDILIST;
do
limitjobs
fluidsynth -ln --fast-render=$TDIR/$M-tmp1.wav
/usr/share/sounds/sf2/FluidR3_GM.sf2 $M.midi &> $TDIR/$M-tmp1.wav.log &
done
echo bursting pdf ...
pdftk $VIDEOSOURCE burst output $TDIR/page%d.pdf
echo synchronizing ...
wait
fluidsynth -ln --fast-render=$TDIR/metronome.wav
/usr/share/sounds/sf2/FluidR3_GM.sf2 $TDIR/metronome.midi &>
$TDIR/metronome.wav.log &
echo "generating temporary h264 files ... "
for P in `seq 1 $MOMENTS`;
do
limitjobs
if [ $DEBUG -ne 0 ] ; then
echo -n "page$P.h264, length: ${ARVT[$P]}s; "
else
echo -n "$P "
fi
gs -dBATCH -dNOPAUSE -q -r495.421 -sDEVICE=pnggray -sOutputFile=-
$TDIR/page$((P)).pdf | \
ffmpeg -y -framerate 1/100000 -i - \
-vf scale=1024:512 -c:v libx264 -tune stillimage -preset ultrafast \
-pix_fmt yuv420p -r 25 -t ${ARVT[$P]} $TDIR/page$((P)).h264 &>
$TDIR/ffmpeg-page$P.pdf-h264.log &
done
echo
echo synchronizing ...
wait
echo normalizing audio data ...
for M in $MIDILIST;
do
limitjobs
sox -v `sox $TDIR/$M-tmp1.wav -n stat -v 2>&1` $TDIR/$M-tmp1.wav
$TDIR/$M-tmp2.wav &> $TDIR/sox-$M-tmp1-tmp2.log &
done
limitjobs
sox -v `sox $TDIR/metronome.wav -n stat -v 2>&1` $TDIR/metronome.wav
$TDIR/metronome-norm.wav &> $TDIR/metronome-norm.wav.log &
echo synchronizing ...
wait
echo adding metronome wav to audio data ...
for M in $MIDILIST;
do
limitjobs
sox $TDIR/metronome-norm.wav $TDIR/$M-tmp2.wav $TDIR/$M-tmp3.wav &>
$TDIR/sox-$M-tmp2-tmp3.log &
done
echo synchronizing ...
wait
echo adding silence to audio data ...
for M in $MIDILIST;
do
limitjobs
sox $TDIR/tsilence.wav $TDIR/$M-tmp3.wav $TDIR/$M.wav &>
$TDIR/sox-$M-tmp2-wav.log &
done
echo synchronizing ...
wait
COUNT=0
for M in $MIDILIST;
do
echo generating $M.mp4 ...
if [ $COUNT -eq 0 ]; then
grep -o "page [[:digit:]]*" videohelper.notes | sort -n -k 2 | sed -e
"s/\(page\) \([[:digit:]]*\)/file \1\2.h264/" > $TDIR/concat.txt
ffmpeg -y -f concat -i $TDIR/concat.txt -i $TDIR/$M.wav -c:v libx264 -tune
stillimage \
-preset $PRESET -pix_fmt yuv420p -r 25 -shortest $M.mp4 &>
$TDIR/ffmpeg-$M.mp4.log
COUNT=$((COUNT+1))
FIRSTVIDEO=$M.mp4
else
limitjobs
ffmpeg -y -i $FIRSTVIDEO -i $TDIR/$M.wav -c:v copy -map 0:v:0 -map 1:a:0
-shortest $M.mp4 &> $TDIR/ffmpeg-$M.mp4.log &
COUNT=$((COUNT+1))
fi
done
echo synchronizing ...
wait
echo removing temporary files ...
if [ $CLEAN -eq 1 ]; then
echo $TDIR | grep "mkvideo-" &> /dev/null
if [ $? -eq 0 ]; then
rm -r $TDIR
fi
fi
%%%% Copyright (C) 2016 Knut Petersen <knut_peter...@t-online.de>
%%%%
%%%% This file contains code derived from Lilypond's ly/event-listener.ly.
%%%% There the following copyright notice was included:
%%%%
%%%% Copyright (C) 2011--2015 Graham Percival <gra...@percival-music.ca>
%%%%
%%%% Other parts of this file are based on code provide by
%%%% Thomas Morley <thomasmorle...@gmail.com>, see
%%%%
http://lilypond.1069038.n5.nabble.com/intercepting-implicit-explicit-page-breaks-td194196.html
%%%%
%%%% Needs at least lilypond version 2.19.23!
%%%%
%%%% This is free software: you can redistribute it and/or modify
%%%% it under the terms of the GNU General Public License as published by
%%%% the Free Software Foundation, either version 3 of the License, or
%%%% (at your option) any later version.
%%%%
%%%% This file is distributed in the hope that it will be useful,
%%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
%%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
%%%% GNU General Public License for more details.
%%%%
%%%% You should have received a copy of the GNU General Public License
%%%% along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
#(define out (open-output-file "videohelper.notes"))
% #(define lastmoment 0.000)
#(define (format-moment moment)
(exact->inexact
(/ (ly:moment-main-numerator moment)
(ly:moment-main-denominator moment))))
#(define (moment-grace->string moment)
"Prints a moment without grace note(s) as a float such as
0.25000. Grace notes are written with the grace duration as a
separate \"dashed\" number, i.e. 0.25000-0.12500. This allows any
program using the output of this function to interpret grace notes
however they want (half duration, quarter duration? before beat,
after beat? etc.)."
(if
(zero? (ly:moment-grace-numerator moment))
(ly:format "~a" (format-moment moment))
;; grace notes have a negative numerator, so no "-" necessary
(ly:format
"~a~a"
(format-moment moment)
(format-moment
(ly:make-moment
(ly:moment-grace-numerator moment)
(ly:moment-grace-denominator moment))))))
#(define (make-output-string-line context values)
"Constructs a tab-separated string beginning with the
score time (derived from the context) and then adding all the
values. The string ends with a newline."
(let* ((moment (ly:context-current-moment context)))
(string-append
(string-join
(append
(list (moment-grace->string moment))
(map
(lambda (x) (ly:format "~a" x))
values))
"\t")
"\n")))
#(define (print-line context . values)
"Prints the list of values (plus the score time) to a file, and
optionally outputs to the console as well. context may be specified
as an engraver for convenience."
(if (ly:translator? context)
(set! context (ly:translator-context context)))
(display (make-output-string-line context values) out)
)
#(define (format-tempo engraver event)
(if (ly:event-property event 'metronome-count)
(print-line engraver "tempo"
( / 60
(* (ly:event-property event 'metronome-count)
(format-moment (ly:duration-length (ly:event-property event
'tempo-unit))))))))
#(define (format-time engraver event)
(print-line engraver "time"))
#(define (format-rest engraver event)
(print-line engraver
"rest"
(format-moment (ly:duration-length
(ly:event-property event 'duration)))
))
#(define (format-note engraver event)
(print-line engraver
"note"
(format-moment (ly:duration-length
(ly:event-property event 'duration)))
))
\layout {
\context {
\Voice
\consists #(make-engraver
(listeners
(tempo-change-event . format-tempo)
(time-signature-event . format-time)
(rest-event . format-rest)
(note-event . format-note)))
}
}
\paper {
#(define (page-post-process layout pages)
(print-pages-first-bar-numbers layout pages #t))
}
#(define* (print-pages-first-bar-numbers layout pages #:optional print-to-file)
(let* ((lines (map (lambda (page) (ly:prob-property page 'lines)) pages))
;; list of systems of each pages
(sys
(map
(lambda (line)
(append-map
(lambda (l)
(let ((system-grob (ly:prob-property l 'system-grob)))
(if (not (null? system-grob))
(list system-grob)
system-grob))
)
line))
lines))
(sys-moment-location
(map
(lambda (m)
(if (and (not (null? m)) (ly:grob? (car m)))
(grob::when (car m))
#f))
sys))
(formatted-output
(map
(lambda (page m)
(if m
(format #f "~a page ~a\n" (format-moment m) page)
(format #f "page ~a contains no music\n" page))
)
(iota (length pages) 1 1)
sys-moment-location))
)
(if (not (null? sys-moment-location))
(begin
(for-each (lambda (i) (display i out)) formatted-output))
(for-each display formatted-output)))
; (format out "lastmoment is ~a\n" lastmoment)
)
#(format out "~a~a~a" "LILYSOURCE=" (ly:parser-output-name) ".ly\n")
pdfforvideo = #(define-void-function () () (format out "~a~a~a" "VIDEOSOURCE="
current-outfile-name ".pdf\n"))
midiforvideo = #(define-void-function () () (format out "~a~a~a" "MIDISOURCE="
current-outfile-name ".midi\n"))
\version "2.19.47"
\include "articulate.ly"
% This file demonstrates how to generate sheet music and video from a single
% lilypond source file. Put it into a directory together with videohelper.ily
% and the mkvideo script, then translate it with
%
% lilypond JSBI1
% ./mkvideo
%
% mkvideo features:
%
% 1. mkvideo is fast as it runs processes in parallel if possible
%
% 2. mkvideo keeps music and audio synchronized even if there are
% tempo changes in the music and if the number of systems per
% page is not constant
%
% Some INSANE tempo changes to test sync algorithm
%
voiceone = \relative c' {
\time 4/4
\set Score.tempoHideNote = ##f
\tempo "Schnell" 4=80
r16 c[d e] f[d e c] g'8[c b^\prall c] d16[g, a b] c[a b g] d'8[g f^\prall g]
e16[a g f] e[g f a] g[f e d] c[e d f] e[d c b] a[c b d] c[b a g] fis[a g b]
\tempo 4=60 % only for testing
a8[d,] c'8.[^\mordent d16] b[a g fis] e[g fis a] g[b a c] b[d c e]
d[b32 c d16 g] b,8[^\prall a16 g] g8 r r4 r16 g[a b] c[a b g] fis8^\prall r
\tempo 4=40 % only for testing
r4 r16 a[b c] d[b c a] b8 r r4 r16 d[c b] a[c b d] c8 r r4 r16 e[d c]
\tempo 4=60 % only for testing
b[d cis e] d8[cis d e] f[a, b! cis] d[fis, gis a] b[c] d4 ~ d16[e, fis gis]
\tempo 4=50 % only for testing
a[fis gis e] e'[d c e] d[c b d] c[a' gis b] a[e f d] gis,[f' e d] c8[b16 a]
a16[a' g f] e[g f a] g2 ~ g16[e f g] a[f g e] f2 ~ f16[g f e] d[f e g]
\tempo 4=80 % only for testing
f2 ~ f16[d e f] g[e f d] e2 ~ e16[c d e] f[d e c] d[e f g] a[f g e] f[g a b]
c[a b g] c8[g] e[d16 c] c[bes a g] f[a g bes] a[b c e,]
\set Score.tempoHideNote = ##t
\tempo 4=65 d [ \tempo 4=50 c' \tempo 4=35 f, \tempo 4=20 b] \tempo 4=60
<c g e>1^\fermata\arpeggio \bar "|."
}
voicetwo = \relative c {
\clef "bass" r2 r16 c[d e] f[d e c] g'8[g,] r4 r16 g'[a b] c[a b g] c8[b c d]
e[g, a b] c[e, fis g] a[b] c4 ~ c16[d, e fis] g[e fis d] g8[b, c d] e[fis g e]
b8.[c16] d8[d,] r16 g[a b] c[a b g] d'8[g fis g] a16[d, e fis] g[e fis d]
a'8[d c d] g,16[\clef "treble" g' f e] d[f e g] f8[e f d] e16[a g f] e[g f a]
g8[f g e] f16[bes a g] f[a g bes] a[g f e] d[f e g] f[e d c] b[d c e] d[c b a]
gis[b a c] \clef "bass" b8[e,] d'8.[^\mordent e16] c[b a g!] fis[a gis b]
a[c b d] c[e d f] e8[a, e' e,] a8[a,] r4 r16 e''16[d c] b[d cis e]
d2 ~ d16[a b c] d[b c a] b2 ~ b16[d c b] a[c b d] c2 ~ c16[g a bes] c[a bes g]
a8[bes a g] f[d' c bes] a[f' e d] e16[d, e f] g[e f d] e8[c d e] f16[d e f]
g8[g,] <c c,>1 _\fermata \arpeggio \bar "|."
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% PRINT version A4
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# ( set-global-staff-size 17.0 )
\book{
\header {
composer = "Johann Sebastian Bach (1685-1750)"
title = "Invention 1"
opus = "BWV 772"
tagline = ##f
}
\paper {
#(set-paper-size "a4")
left-margin = 1.5\cm
line-width = 18\cm
top-margin = 1.5\cm
bottom-margin = 1.5\cm
horizontal-shift = 0\mm
ragged-bottom = ##f
ragged-last-bottom = ##f
print-page-number = ##f
}
\score {
\new PianoStaff <<
\set PianoStaff.connectArpeggios = ##t
\context Staff = "one" << \voiceone >>
\context Staff = "two" << \voicetwo >>
>>
\layout{
indent = 0.0
}
}
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% VIDEO version
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#(set! paper-alist (cons '("video" . (cons (* 21 cm) (* 10.5 cm))) paper-alist))
\include "videohelper.ily"
# ( set-global-staff-size 24 )
\book{
\header {
title = \markup \center-column {
\line \bold \fontsize #5 { Invention 1 } \vspace #.25
\line \bold \fontsize #2 { Johann Sebastian Bach } \vspace #.5
\line \medium \fontsize #0 { Video made with the help of Lilypond}
\line \medium \fontsize #0 { and other open source tools.} \vspace #.5
\line \medium \fontsize #0 { Demonstrates how to synchronize video and audio even in }
\line \medium \fontsize #0 { the presence of tempo changes and in case of a variable}
\line \medium \fontsize #0 { number of systems per page.}
}
tagline = ##f
}
\paper {
#(set-paper-size "video")
left-margin = 1\cm
line-width = 19.5\cm
top-margin = 1\cm
bottom-margin = 1\cm
horizontal-shift = 0\mm
ragged-bottom = ##f
ragged-last-bottom = ##f
print-page-number = ##f
max-systems-per-page = #2
}
\pageBreak
\score {
\new PianoStaff <<
\set PianoStaff.connectArpeggios = ##t
\context Staff = "one" << \voiceone >>
\context Staff = "two" << \voicetwo >>
>>
\layout{
indent = 0.0
}
}
} \pdfforvideo
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% MIDI
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
panmidi = { \set Staff.midiInstrument = #"pan flute"
\set Staff.midiMinimumVolume = #0.2
\set Staff.midiMaximumVolume = #0.2
}
pianomidi = { \set Staff.midiInstrument = #"acoustic grand"
\set Staff.midiMinimumVolume = #0.2
\set Staff.midiMaximumVolume = #0.2
}
\book{
\score {
\unfoldRepeats \articulate <<
\new PianoStaff <<
\set PianoStaff.connectArpeggios = ##t
\context Staff = "one" << {\panmidi \voiceone {r1*3 \tempo 1 = 1}} >>
\context Staff = "two" << {\panmidi \voicetwo} >>
>>
>>
\midi {
\context {
\Score
midiMinimumVolume = #0.0
midiMaximumVolume = #1.0
}
}
}
} \midiforvideo
\book{
\score {
\unfoldRepeats \articulate <<
\new PianoStaff <<
\set PianoStaff.connectArpeggios = ##t
\context Staff = "one" << {\pianomidi \voiceone {r1*3 \tempo 1 = 1}} >>
\context Staff = "two" << {\pianomidi \voicetwo} >>
>>
>>
\midi {
\context {
\Score
midiMinimumVolume = #0.0
midiMaximumVolume = #1.0
}
}
}
} \midiforvideo
_______________________________________________
lilypond-user mailing list
lilypond-user@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-user