Hi everybody! To generate score videos like Bach: Invention 1 <https://www.youtube.com/watch?v=EqWYmrwTcqQ>, Wolf: Resignation <https://www.youtube.com/watch?v=IonPmbdY7ME> and Peterson-Berger: I Fyrreskoven <https://www.youtube.com/watch?v=hgDWprKiyo0> that give a different color to notes and rest while they are active you might use the attached files if you run a unixoid system like linux.
mkvideo-lily-diff contains changes to an installed version of lilypond (tested with 2.19.65, but it also should work with much older versions). No recompilation is necessary, only scm and ps files are changed. The patched version of lilypond will behave exactly like the unpatched version as long as videohelper.ily is not used. One exception: If you define illegal rgb colors (R,G,B not in the range [0.0 ... 1.0]) this will not be detected. Wolf_Resignation.ly is a lilypond score that demonstrates the intended use. Be sure to have a close look at the comments! videohelper.ily includes some definitions needed for video generation. mkvideo requires bash, ls, sort, tail, uniq, grep, sed, usleep, bc, gs, pdftk, lilypond, fluidsynth, sox, ffmpeg, wc and a suitable sound font, e.g. FluidR3_GM.sf2 1. Patch some of the scm and ps files of your version of lilypond. Adapt the paths first! cd /some/path/lilypond/2.19.65 patch -p 1 < /some/path/mkvideo-lily-diff 2. Store the other files in a separate directory and feed lilypond: lilypond Wolf_Resignation 3. Run the mkvideo script: ./mkvideo At the top of mkvideo there are some definitions that might be changed ... be sure to define a suitable soundfont. If you have problems: DEBUG gives a very verbose output, clean keeps temporary files. cu, Knut
diff -U 4 ./origscm/framework-ps.scm ./scm/framework-ps.scm --- ./origscm/framework-ps.scm 2016-11-21 05:26:10.890701666 +0100 +++ ./scm/framework-ps.scm 2017-07-20 06:43:33.177169912 +0200 @@ -108,9 +108,14 @@ (output-entry "page-width" 'paper-width) (if (ly:get-option 'strokeadjust) "true setstrokeadjust\n" "") )) +;; [mkvideo] This version of dump-page is extended for mkvideo. +;; As long as null? videopagelist is true nothing changes. (define (dump-page outputter page page-number page-count landscape?) + (let* ( + (ml (assoc page-number videopagelist)) + (rep? (and (not (null? videopagelist)) (if (pair? ml) (not (null? (cdr ml))) #f)))) (ly:outputter-dump-string outputter (string-append (format #f "%%Page: ~a ~a\n" page-number page-number) @@ -119,8 +124,9 @@ "page-width output-scale lily-output-units mul mul 0 translate 90 rotate\n" "") "%%EndPageSetup\n" "\n" + (format #f (if rep? "/lilypage {\n" "")) "gsave 0 paper-height translate set-ps-scale-to-lily-scale\n" "/helpEmmentaler-Brace where {pop helpEmmentaler-Brace} if\n" "/helpEmmentaler-11 where {pop helpEmmentaler-11} if\n" "/helpEmmentaler-13 where {pop helpEmmentaler-13} if\n" @@ -130,9 +136,15 @@ "/helpEmmentaler-20 where {pop helpEmmentaler-20} if\n" "/helpEmmentaler-23 where {pop helpEmmentaler-23} if\n" "/helpEmmentaler-26 where {pop helpEmmentaler-26} if\n")) (ly:outputter-dump-stencil outputter page) - (ly:outputter-dump-string outputter "stroke grestore\nshowpage\n")) + (ly:outputter-dump-string outputter "stroke grestore\nshowpage\n") + (if rep? (list + (ly:outputter-dump-string outputter (format #f "} def 1 ")) + (do ((i 0 (1+ i))) + ((>= i (length (cdr ml)))) + (ly:outputter-dump-string outputter (format #f "~a " (list-ref (cdr ml) i)))) + (ly:outputter-dump-string outputter (format #f " { /MkVidTime exch def MkVidTime 1 eq { exit } if lilypage } loop\n" )))))) (define (supplies-or-needs paper load-fonts?) (define (extract-names font) (if (ly:pango-font? font) diff -U 4 ./origscm/output-lib.scm ./scm/output-lib.scm --- ./origscm/output-lib.scm 2017-02-03 06:54:22.841211149 +0100 +++ ./scm/output-lib.scm 2017-07-20 06:34:08.286750353 +0200 @@ -703,13 +703,14 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Color +;; [mkvideo] This version of color? does _not_ check that +;; r, g and b are in the range [0.0 .. 1.0]! (define-public (color? x) (and (list? x) (= 3 (length x)) - (every number? x) - (every (lambda (y) (<= 0 y 1)) x))) + (every number? x))) (define-public (rgb-color r g b) (list r g b)) ;; predefined colors diff -U 4 ./origscm/output-ps.scm ./scm/output-ps.scm --- ./origscm/output-ps.scm 2016-11-21 05:26:10.894702197 +0100 +++ ./scm/output-ps.scm 2017-07-20 06:35:48.233783884 +0200 @@ -204,10 +204,11 @@ (ly:format "~4l draw_round_box" (list width height x y blotdiam)))) ;; save current color on stack and set new color +;; [mkvideo] This version of setcolor extends the precision (define (setcolor r g b) - (ly:format "gsave ~4l setrgbcolor\n" + (ly:format "gsave ~9l setrgbcolor\n" (list r g b))) ;; restore color from stack (define (resetcolor) "grestore\n") diff -U 4 ./origscm/paper.scm ./scm/paper.scm --- ./origscm/paper.scm 2016-11-21 05:26:10.898702727 +0100 +++ ./scm/paper.scm 2017-07-14 09:51:45.322354046 +0200 @@ -17,8 +17,10 @@ ;; for define-safe-public when byte-compiling using Guile V2 (use-modules (scm safe-utility-defs)) +(define-public videopagelist '()) + (define-public (set-paper-dimension-variables mod) (module-define! mod 'dimension-variables '(binding-offset blot-diameter diff -U 4 ./origps/music-drawing-routines.ps ./ps/music-drawing-routines.ps --- ./origps/music-drawing-routines.ps 2016-05-22 19:27:33.908557943 +0200 +++ ./ps/music-drawing-routines.ps 2017-07-20 06:21:39.838577836 +0200 @@ -307,5 +307,33 @@ moveto %w 0 rmoveto }repeat }bind def + +/MKVIDcolor { 0.7 0.0 1.0 } def % color to use + % +/MKVIDmagic { 2.0 } def % magic value for our own coloring requests + % +/MKVIDsetrgbcolor { % the extended setrgbcolor + 3 dict begin % start local name space + /Stop exch def % local "blue": stop + /Start exch def % local "green": start + /Red exch def % local "red": magic + Red MKVIDmagic eq % if (Red = MKVIDmagic) ( + { Start MkVidTime eq % if (start = current time) + { MKVIDcolor ORIGsetrgbcolor} % change color to red + { Start MkVidTime gt % else if ((start > current time) + { Stop MkVidTime lt % and (stop < current time)) + { MKVIDcolor ORIGsetrgbcolor } % change color to red + if } % else + if } % do not change color + ifelse } % + { Red Start Stop ORIGsetrgbcolor } % ) else change color as requested + ifelse % + end % stop local namespace +} def % + % +/ORIGsetrgbcolor /setrgbcolor load def % make original setrgbcolor available as /ORIGsetrgbcolor + % +/setrgbcolor { MKVIDsetrgbcolor } bind def % redefine setrgbcolor + %end music-drawing-routines.ps
#(define mkvid_out (open-output-file "videohelper.notes")) #(format mkvid_out "~a~a~a" "LILYSOURCE=" (ly:parser-output-name) ".ly\n") pdfforvideo = #(define-void-function () () (format mkvid_out "~a~a~a" "VIDEOSOURCE=" current-outfile-name ".pdf\n")) midiforvideo = #(define-void-function () () (format mkvid_out "~a~a~a" "MIDISOURCE=" current-outfile-name ".midi\n")) videoResolution = #(define-void-function (parser location x y) (number? number?) (format mkvid_out "VIDEORESOLUTION=~ax~a\n" x y)) videoPreset = #(define-void-function (parser location p) (string?) (format mkvid_out "PRESET=~a\n" p)) audioBitRate = #(define-void-function (parser location p) (string?) (format mkvid_out "AUDIOBITRATE=~a\n" p)) #(define pagerepetitions? #t) #(define colorflags? #t) #(define colorstems? #t) #(define colordots? #t) #(define colorheads? #t) noPageRepetitions = #(define-void-function () () (list (set! pagerepetitions? #f) (format mkvid_out "NOPAGEREPETITIONS\n"))) noColorFlags = #(define-void-function () () (set! colorflags? #f)) noColorStems = #(define-void-function () () (set! colorstems? #f)) noColorDots = #(define-void-function () () (set! colordots? #f)) noColorHeads = #(define-void-function () () (set! colorheads? #f)) #(define (format-moment moment) (exact->inexact (/ (ly:moment-main-numerator moment) (ly:moment-main-denominator moment)))) #(define tempolist '()) #(define (format-tempo engraver event) (let* ( (metrocount (ly:event-property event 'metronome-count)) (tempounit (ly:event-property event 'tempo-unit)) (seconds (/ 60 (* metrocount (format-moment (ly:duration-length tempounit))))) (time (ly:context-current-moment (ly:translator-context engraver))) (moment (+ 0.0 (ly:moment-main time) (* (ly:moment-grace time) (/ 9 40))))) (if metrocount (format mkvid_out "~a tempo ~f\n" moment seconds)))) #(define (format-time engraver event) (let* ( (numerator (ly:event-property event 'numerator)) (denominator (ly:event-property event 'denominator)) (time (ly:context-current-moment (ly:translator-context engraver))) (moment (+ 0.0 (ly:moment-main time) (* (ly:moment-grace time) (/ 9 40))))) (format mkvid_out "~a time ~a ~a\n" moment numerator denominator))) \layout { \context { \Staff \consists #(make-engraver (listeners (time-signature-event . format-time))) } \context { \Voice \consists #(make-engraver (listeners (tempo-change-event . format-tempo))) } } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Color notes and rests % #(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 (pitch-to-string p) (let* ( (nn (ly:pitch-notename p)) (nn-string (list-ref '("c" "d" "e" "f" "g" "a" "h") nn)) (alt (ly:pitch-alteration p)) (alt-num (+ 2 (* 2 alt))) (alt-string (list-ref '("eses" "es" "" "is" "isis") alt-num)) (oct (ly:pitch-octave p)) (oct-num (+ 5 oct)) (oct-string (list-ref '(",,,," ",,," ",," "," "" "'" "''" "'''" "''''" "'''''" "''''''") oct-num)) (na (cons nn alt)) (test (lambda (n a) (equal? na (cons n a)))) (na-string (cond ((test 2 -1) "eses") ((test 2 -1/2) "es") ((test 5 -1) "asas") ((test 5 -1/2) "as") ((test 6 -1/2) "b") (else (string-append nn-string alt-string))))) (string-append na-string oct-string))) #(define maxstop 0.0) % maximum Moment #(define startlist '()) % Liste aller Startmomente von Noten oder Pausen #(define firstmomentlist '()) % Liste aller ersten Momente jeder Seite #(define (mkvideo-dump grob) (let* ( (pap (ly:parser-lookup '$defaultpaper)) (paper-column (grob-get-paper-column grob)) (cause (ly:grob-property grob 'cause)) (pitch (if (ly:prob? cause) (ly:event-property cause 'pitch))) (lilypitch (if (ly:pitch? pitch) (pitch-to-string pitch) "NaP")) (type (if (ly:pitch? pitch) "note" "rest")) (time (ly:grob-property paper-column 'when 0)) (start (+ 0.0 (ly:moment-main time) (* (ly:moment-grace time) (/ 9 40)))) (duration (if (ly:prob? cause) (format-moment (ly:duration-length (ly:event-property cause 'duration))) 0.0)) (stop (+ start duration)) (nstart (- 0 start)) (nstop (- 0 stop)) (stem (ly:grob-object grob 'stem)) (flag (ly:grob-object grob 'flag)) (dot (ly:grob-object grob 'dot)) (R (if pagerepetitions? 2.0 0.6)) (G (if pagerepetitions? nstart 0.0)) (B (if pagerepetitions? nstop 1.0))) (if (not (equal? (ly:grob-property grob 'transparent) #t)) (format mkvid_out "~f ~a ~f ~a\n" start type stop lilypitch)) (if (equal? (member nstart startlist) #f) ( list (set! startlist (append startlist (list nstart))) (set! startlist (sort-list startlist >=)))) (if (> maxstop nstop) (set! maxstop nstop)) (list (if colorheads? (ly:grob-set-property! grob 'color (rgb-color R G B))) (if (and (not (null? stem)) colorstems?) (ly:grob-set-property! stem 'color (rgb-color R G B))) (if (and (not (null? flag)) colorflags?) (ly:grob-set-property! flag 'color (rgb-color R G B))) (if (and (not (null? dot)) colordots?) (ly:grob-set-property! dot 'color (rgb-color R G B)))))) \layout { \context { \Voice \override NoteHead #'after-line-breaking = #mkvideo-dump \override Rest #'after-line-breaking = #mkvideo-dump \override MultiMeasureRest #'after-line-breaking = #mkvideo-dump \override NoteHead.layer = 3 } } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Here we do some post-processing and build the alist for the page dumper % (key is the page number, value is the list of moments on the page) % #(define dumpedstartlist? #f) #(define (dumpstartlist) (list (do ((i 0 (1+ i))) ((>= i (length startlist))) ( format mkvid_out "~a page\n" (- 0 (list-ref startlist i)))) (format mkvid_out "LASTMOMENT=~a\n" (- 0 maxstop)) (set! dumpedstartlist? #t))) #(define (after-pb-processing layout pages) (let* ( (lines (map (lambda (page) (ly:prob-property page 'lines)) pages)) (systems (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)) (firstmoments (append (map (lambda (m) (if (and (not (null? m)) (ly:grob? (car m))) (- 0 (format-moment (grob::when (car m)))) #f)) systems) (list maxstop))) (moments (append startlist (list maxstop)))) (if (and (not (null? firstmoments)) pagerepetitions?) (map (lambda (page m) (if m (set! videopagelist (acons page (cdr (member (list-ref firstmoments page) (reverse (member m moments)))) videopagelist)) (list (if (not dumpedstartlist?) (dumpstartlist)) (set! videopagelist (acons page '() videopagelist )) (format mkvid_out "page ~a contains no music\n" page) ) ) ) (iota (length pages) 1 1) firstmoments)))) \paper { #(define (page-post-process layout pages) (after-pb-processing layout pages)) }
#!/bin/bash ###################################################################### # Copyright (C) 2016-2017 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. ###################################################################### VERSION=2017-07-21 # FPS=n: video files will use n frames per second # Currently FSP != 25 is broken. It's either ffmpeg or I am too # blind to see my mistake ;-( FPS=25 VIDEORESOLUTION=1280x720 PRESET=veryslow AUDIOBITRATE=128k # TITLETIME: number of seconds the title page shall be visible TITLETIME=4.0 # AFTERTIME AFTERTIME=6.666 # DEBUG: n != 0 turns on debugging mode (verbose output) DEBUG=0 # CLEAN: n != 0 enables deletion of all temporary files CLEAN=1 # SOUNDFONTB=./kptestpiano.sf2 SOUNDFONTA=/usr/share/sounds/sf2/FluidR3_GM.sf2 SOUNDFONTS="$SOUNDFONTA $SOUNDFONTB" 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 This is mkvideo version $VERSION echo checking dependencies ... weneedprog ls sort tail uniq grep sed usleep bc gs pdftk lilypond fluidsynth sox ffmpeg weneeddata $SOUNDFONTS 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 } grep "NOPAGEREPETITIONS" videohelper.notes &> /dev/null if [ $? -eq 0 ]; then echo "No video generation because \noPageRepetitions was used!" exit fi echo checking videohelper.notes ... checknotes "LILYSOURCE" "LILYSOURCE undefined" checknotes "VIDEOSOURCE" "VIDEOSOURCE undefined" checknotes "MIDISOURCE" "MIDISOURCE undefined" checknotes "tempo" "no tempo definition" checknotes "time" "no time definition" 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` eval `grep LASTMOMENT videohelper.notes` grep VIDEORESOLUTION videohelper.notes &> /dev/null if [ $? -eq 0 ]; then eval `grep VIDEORESOLUTION videohelper.notes` fi grep PRESET videohelper.notes &> /dev/null if [ $? -eq 0 ]; then eval `grep PRESET videohelper.notes` fi grep AUDIOBITRATE videohelper.notes &> /dev/null if [ $? -eq 0 ]; then eval `grep AUDIOBITRATE videohelper.notes` fi MIDILIST=`grep MIDISOURCE videohelper.notes | sed -e "s/MIDISOURCE=\([[:print:]]*\).midi/\1/" | sort | uniq | sed ':a;N;$!ba;s/\n/ /g'` 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:]]//"` TIMENUMERATOR=`grep time videohelper.notes | sort -n | head -n 1 | sed -e "s/[0-9.]*[[:space:]]time[[:space:]]\([0-9][0-9]*\)[[:space:]]\([0-9][0-9]*\)/\1/"` TIMEDENOMINATOR=`grep time videohelper.notes | sort -n | head -n 1 | sed -e "s/[0-9.]*[[:space:]]time[[:space:]]\([0-9][0-9]*\)[[:space:]]\([0-9][0-9]*\)/\2/"` ARVT[1]=$TITLETIME for M in `seq 1 $PAGES`; do ARVT[$((M+1))]=`bc <<<${ARTIMES[$((M+1))]}-${ARTIMES[$M]} | sed -r 's/^(-?)\./\10./'` done ARVT[$MOMENTS]=`bc <<<${ARVT[$MOMENTS]}+$AFTERTIME` ARVT[2]=`bc -l <<<${ARVT[2]}+$METROTIME*$TIMENUMERATOR/$TIMEDENOMINATOR` 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.55\" \score { \drums { \repeat unfold $TIMENUMERATOR { wbl$TIMEDENOMINATOR } } \midi { \tempo 4 = $FIRSTTEMPO } }" > $TDIR/metronome.ly cd $TDIR lilypond metronome.ly &> /dev/null & cd .. echo generating tsilence.wav ... sox -n -r 48000 -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 -o synth.sample-rate=48000 -ln --fast-render=$TDIR/$M-tmp1.wav $SOUNDFONTS $M.midi &> $TDIR/$M-tmp1.wav.log & done echo bursting pdf ... pdftk $VIDEOSOURCE burst output $TDIR/page%d.pdf echo synchronizing ... wait fluidsynth -o synth.sample-rate=48000 -ln --fast-render=$TDIR/metronome.wav $SOUNDFONTS $TDIR/metronome.midi &> $TDIR/metronome.wav.log & echo "generating `grep page videohelper.notes | wc | sed -e "s/[[:space:]]*\([0-9]*\)[[:space:]]*[[:print:]]*/\1/"` 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=png256 -sOutputFile=- $TDIR/page$((P)).pdf | \ ffmpeg -y -framerate 1/10000 -i - \ -vf scale=$VIDEORESOLUTION -c:v libx264 -tune stillimage -preset ultrafast \ -pix_fmt yuv420p -r $FPS -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 ls -1 $TDIR/page*.h264 | grep -o "page[[:print:]]*h264" | sed -e "s/page//" | LANG=clang sort -n | sed -e "s/\([[:print:]]*\)/file page\1/" > $TDIR/concat.txt ffmpeg -y -f concat -i $TDIR/concat.txt -i $TDIR/$M.wav -c:v libx264 -tune animation \ -preset $PRESET -movflags +faststart -bf 2 -flags +cgop -pix_fmt yuv420p -r $FPS -c:a aac -b:a $AUDIOBITRATE -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 -movflags +faststart -c:a aac -b:a $AUDIOBITRATE -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
% % Demo for mkvideo % % This file defines % - an A4 score (four pages) % - individual sheets for all voices (one page each) % % - one score to be used for video generation \ These will be combined % - five midi files for video generation / to five mp4 videos % % Patch your version of lilypond first, then run % % lilypond Wolf_Resignation % ./mkvideo % % The five videos produced by mkvideo are relatively small (about 4.5M each), % but a lot of temporary data is written to disk (more than 800M). % \version "2.19.65" \include "deutsch.ly" #(ly:set-option 'point-and-click #f) globMus = { #(set-accidental-style 'modern-cautionary) \autoBeamOff \dynamicUp \set Score.tempoHideNote = ##t \override Hairpin.to-barline = ##t \key f \major \time 4/4 \partial 4 } sopMusic = \relative c'' { \set Staff.instrumentName = \markup { \bold "Sopran " } c4\p a4. a8 b4\< d\> d\! (c8) b a4 f\pp f f f f g4. a8 g4 b a4. e8 cis4 dis e4. (fis8) e4 a4\p a4. a8 g4 g fis4. fis8 f4\< b ~ b b8 b des4 des es4. es8 eses4 des des4.\f\> b8 ges4 as f2\p ges4 r r2 r4 a8\p\< [(h)]\! c4. c,8\> h4 a'\! a4. gis8 gis4 h8\< [(cis)] d4. d8 cis4\> h h4\! (b8) a a4\< as8 [(des)] des4.\mf ces8 b4\> as ges4.\p (f8) es4\! r8^\fermata des8\pp des4 ges b8 (ges'4) f8 es4. des8 ces4\< ces ~ ces\> b8 as\! ges4 f b4.\> f8\! ges4 ges\pp ges4. ges8 ges4 f f^\markup {\bold\italic "ritardando"} (e8 [f]) e2 r2 r4^\markup {\bold\italic "a tempo"} c'4\p a4. a8 b4\< d d\> (c8)\! b a4 f\pp f f f f g4. a8 g4 b a4. e8 cis4 dis e4. (fis8) e4 a4\p a4. a8 g4\< g b4 (a8) g a2 c4\f c8\< c d4 d d4.\ff d8 e4\> e f4.\p e8 e8 [(d)] c4 c4 (b8 [c16 b]) a4 r8 f8\pp f4. f8 c' [(b)] a4 <<g2{s4\<s4\>}>> f4\! \bar "|." } altMusic = \relative c' { \set Staff.instrumentName = \markup { \bold "Alt " } c4\p c8 [(d e)] f b\< [(a)] g\> [(f)] f\! [(e f)] g g [(f)]a,4\pp b a d d f8 [(e)] f4 c c cis4. cis8 cis4 h h4. (d8 ~ d [cis]) cis e\p f4. f8 es4 es d4. d8 d\< [(es)] e [(f)] ges4 f f fes es4. es8 ges4 ces b4.\f ges8\> es4 es es4\p (des8 [ces]) b4\! r r1 r4 dis8\mf (e) fis4.\> fis8 eis4.\p eis8 eis4 fis fis\< gis8 [(a)] h4 eis,8 [(fis)] g4\> g g8\< [(fis)] f4 f8\mf [(fes)] es4 d8\> d es f es4\p ( d) es\! r8^\fermata ces8\pp b4 des ges ges ges b ces\< fes,8 [(f)] ges4\> f8 [(es)]\! es4 ces d\> b\! b f'8\pp [(es)] des4. es8 des4 des c4. (h8) b2 r2 r4 c4\p c8 [(d e)] f b\< [(a)] g [(f)] f\> [(e f)]\! g g [(f)] a,4\pp b a d d f8 [(e)] f4 c4 c cis4. cis8 cis4 h h4. (d8 ~ [d cis]) cis e\p f4. f8 f4\< f f e g (f) f\f\< f8 f f4 b h4.\ff g8 gis4\> g f4.\p f8 f4 f d (e) g f\pp c (d8) es f4 f f8 [\< (e16 d c8\> b]) a4\! \bar "|." } tenMusic = \relative c' { \set Staff.instrumentName = \markup { \bold "Tenor " } \clef "G_8" c4\p c4. c8 f4\< b,\> b\! (g8) e a4 f'8\pp [(e)] e [(d)] d [(c)] c (b4) a8 c4. h8 b8 [(c)] d [(dis)] fis [(e cis)] a a [(ais h)] a a [(gis16 fis e8 gis]) a4 cis4\p c4. c8 b4 b h a gis8\< [(a)] b [(ces)] des4 des ges, ges ges ges heses as8 [(f')] ges4.\f des8\> b4 ces as2\p ges4 r r4 fis8\p\< [(gis)] a4 c8 [(h)] a4.\! g8\> fis4 h h\! h8 [(cis)] d4 d h4 h gis\< cis8 [(d)] es4\> d cis8\< [(c)] h4 b\mf ces ges2\> (b4\p as) ges r8^\fermata f8\pp ges4 b des b ces fes fes8\< [(es)] ces4 es\> d8 [(es)]\! as,4 as as4.\> as8\! ges4 ges\pp b4. ges8 b4 b a4 (g) g2 r2 r4 c4\p c4. c8 f4\< b, b\> (g8)\! e a4 f'8\pp [(e)] e [(d)] d [(c)] c (b4) a8 c4. h8 b8 [(c)] d [(dis)] fis [(e cis)] a a [(ais)] h [(a)] a [(gis16 fis e8 gis)] a4\! cis\p c4. c8\< d4 h b b a2 a4\f\< a8 a b4 f' g4.\ff h,8 h4\> b c4.\p a8 b4 f f (g) e a\pp a4. a8 d4 f, c'\< (e,)\> f\! \bar "|." } basMusic = \relative c' { \set Staff.instrumentName = \markup { \bold "Baà " } \clef "bass" c4\p f,4. es8 d4\< b\> g\! (c8) cis d4 f, \pp g a b h c d e r r4 r8 a8 fis4 f e2 a,4 a'4\p f f, g g gis (a8) a b8\< [(h16 c)] des4 ges, ges b b ces4 ces c des ges4.\f f8\> es4 ces des2\p ges,4 fis8\p [(gis)] a4.\< his8 cis4 dis fis4.\> e8 dis4 h8\< [(cis)] d4\> cis\! h a gis fis eis gis a e' es\< d8 [(des)] ges4\mf (ces,2.\> b2\p) ces4 r8^\fermata des8\pp ges4 ges ges es ces ges' g\< (as) a4\> b8 ces\! c4 des b,\> d\! es ces\pp ges4. ces8 ges4 b f (c'8 [g)] c2 r2 r4 c'\p f,4. es8 d4\< b g\> (c8)\! cis d4 f,\pp g a b h c d e r r4 r8 a8 fis4 f e2 a,4 a\p f a h\< d g, c cis d8 [(e)] f4\f\< f b b g4.\ff g8 e4\> c a4.\p c8 b4 a g (c) cis d\pp es4 (d8) cis d4 c8 [(a16 b)] <<c2{s4\<s4\>}>> f,4\! \bar "|." } lA = \lyricmode { Komm, Trost der Welt, du stil -- le Nacht! Wie steigst du von den Ber -- gen sacht, die Lüf -- te } lB = \lyricmode { al -- le } lC = \lyricmode { schla -- fen; ein Schif -- fer nur noch, wan -- der -- müd', singt ü -- bers Meer sein A -- bend -- lied zu Got -- tes Lob im Ha -- fen. Die Jah -- re wie die Wol -- ken geh'n und las -- sen mich hier ein -- sam steh'n, die Welt hat mich ver -- ges -- sen, da trat'st du wun -- der -- bar zu mir, als ich beim Wal -- des -- rau -- schen hier ge -- dan -- ken -- voll ge -- ses -- sen. O Trost der Welt, du stil -- le Nacht! Der Tag hat mich so müd' ge -- macht, das } lD = \lyricmode { wei -- te } lE = \lyricmode { Meer schon dun -- kelt; laÃ' aus -- ruhn mich von Lust und Not, bis daà das ew' -- ge Mor -- gen -- rot den stil -- len Wald durch -- fun -- kelt, den stil -- len Wald durch -- fun -- kelt. } satWords = \lyricmode { \lA \lB \lC \lD \lE } bWords = \lyricmode { \lA \lC \lE } % % Some global definitions for header, paper and layout % \header { tagline = ##f } #(set-global-staff-size 17) \paper { #(set-paper-size "a4") left-margin = 2.0\cm binding-offset = 0\cm line-width = 17\cm top-margin = 1.7\cm bottom-margin = 1.5\cm horizontal-shift =0\mm ragged-bottom = ##f ragged-last-bottom = ##f print-page-number = ##f annotate-spacing=##f } \layout { \context{ \StaffGroup \override StaffGrouper #'staff-staff-spacing = #'((basic-distance . 0) (minimum-distance . 0) (padding . 0) (stretchability . 0)) \override StaffGrouper #'staffgroup-staff-spacing = #'((basic-distance . 0) (minimum-distance . 0) (padding . 0) (stretchability . 0)) } \context{ \Staff \override VerticalAxisGroup #'staff-staff-spacing = #'((basic-distance . 0) (minimum-distance . 10) (padding . 0) (stretchability . 0)) \override VerticalAxisGroup #'nonstaff-relatedstaff-spacing = #'((basic-distance . 0) (minimum-distance . 0) (padding . 0) (stretchability . 0)) \override VerticalAxisGroup #'nonstaff-unrelatedstaff-spacing = #'((basic-distance . 0) (minimum-distance . 0) (padding . 0) (stretchability . 0)) } \context{ \Lyrics \override LyricText #'font-size = #'0.0 %\override LyricText #'font-size = #'1.0 %\override LyricText #'font-name = "Tele-Antiqua" \override LyricHyphen #'minimum-distance = #0.6 \override LyricHyphen #'padding = #0.1 \override LyricHyphen #'dash-period = #12 \override VerticalAxisGroup #'nonstaff-relatedstaff-spacing = #'((basic-distance . 0) (minimum-distance . 0) (padding . 0.8) (stretchability . 10)) \override VerticalAxisGroup #'nonstaff-nonstaff-spacing = #'((basic-distance . 0) (minimum-distance . 0) (padding . 0.0) (stretchability . 0)) \override VerticalAxisGroup #'nonstaff-unrelatedstaff-spacing = #'((basic-distance . 0) (minimum-distance . 0) (padding . 1.5) (stretchability . 100)) } } % % The Score to be printed on A4 % \book { \bookOutputSuffix "Partitur" \paper { page-count = #4 } \markup { \general-align #X #LEFT \bold { \column { \fontsize #+2 \fill-line { {"Hugo Wolf: Sechs geistliche Lieder"} { "Partitur" }} \fontsize #+0 { "nach Gedichten von Joseph von Eichendorff" } \fontsize #-3 { " " } \fontsize #+4 { "Nr. 3: Resignation" } \fontsize #+5 { " " }}}} \score { \new ChoirStaff << \new Staff {\new Voice = sop {\globMus \tempo "MäÃig langsam" 4=63 \sopMusic}}\new Lyrics \with{}\lyricsto sop {\satWords} \new Staff {\new Voice = alt {\globMus \altMusic}}\new Lyrics \with{}\lyricsto alt {\satWords} \new Staff {\new Voice = ten {\globMus \tenMusic}}\new Lyrics \with{}\lyricsto ten {\satWords} \new Staff {\new Voice = bas {\globMus \basMusic}}\new Lyrics \with{}\lyricsto bas {\bWords} >> \layout{ system-count = #12 \context { \Voice \consists "Ambitus_engraver" } } } } % % Single Voices to be printed on A4 % \book { \bookOutputSuffix "Auszug-Sopran" \markup { \general-align #X #LEFT \bold { \column { \fontsize #+2 \fill-line { {"Hugo Wolf: Sechs geistliche Lieder"} { "Sopran" }} \fontsize #+0 {"nach Gedichten von Joseph von Eichendorff"} \fontsize #-3 { " " } \fontsize #+4 { "Nr. 3: Resignation" } \fontsize #+5 { " " }}}} \score { \new Staff { \globMus \tempo "MäÃig langsam" 4=63 \sopMusic } \addlyrics \satWords \layout { system-count = #10 }} } \book { \bookOutputSuffix "Auszug-Alt" \markup { \general-align #X #LEFT \bold { \column { \fontsize #+2 \fill-line { {"Hugo Wolf: Sechs geistliche Lieder"} { "Alt" }} \fontsize #+0 {"nach Gedichten von Joseph von Eichendorff"} \fontsize #-3 { " " } \fontsize #+4 { "Nr. 3: Resignation" } \fontsize #+5 { " " }}}} \score { \new Staff { \globMus \tempo "MäÃig langsam" 4=63 \altMusic } \addlyrics \satWords \layout { system-count = #10 }} } \book { \bookOutputSuffix "Auszug-Tenor" \markup { \general-align #X #LEFT \bold { \column { \fontsize #+2 \fill-line { {"Hugo Wolf: Sechs geistliche Lieder"} { "Tenor" }} \fontsize #+0 {"nach Gedichten von Joseph von Eichendorff"} \fontsize #-3 { " " } \fontsize #+4 { "Nr. 3: Resignation" } \fontsize #+5 { " " }}}} \score { \new Staff { \globMus \tempo "MäÃig langsam" 4=63 \tenMusic } \addlyrics \satWords \layout { system-count = #10 }} } \book { \bookOutputSuffix "Auszug-Bass" \markup { \general-align #X #LEFT \bold { \column { \fontsize #+2 \fill-line { {"Hugo Wolf: Sechs geistliche Lieder"} { "BaÃ" }} \fontsize #+0 {"nach Gedichten von Joseph von Eichendorff"} \fontsize #-3 { " " } \fontsize #+4 { "Nr. 3: Resignation" } \fontsize #+5 { " " }}}} \score { \new Staff { \globMus \tempo "MäÃig langsam" 4=63 \basMusic } \addlyrics \bWords \layout { system-count = #10 }} } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Video % #(set-global-staff-size 19) #(set! paper-alist (cons '("video" . (cons (* 21 cm) (* 11.8125 cm))) paper-alist)) % We need a 16:9 paper format \include "videohelper.ily" % include only _once_. Exactly one score with \layout {...} must follow, at least one score with \midi {...} must follow. %\noPageRepetitions % If you use noPageRepetitions there will be a pdf with all objects that change color dependent on moment colored, % but _without_ repeated pages. Use as long as you tune the score layout. %\noColorStems % Don't give color to stems and flags %\noColorDots % Don't give color to dots %\noColorHeads % Don't color notehedas % The following three commands might be used to override defaults defined in the mkvideo script: % #(videoResolution 1280 720 ) % Defaults to 1280 x 720. Use default, 1920x1080, 1024x576 or other resolutions. #(videoPreset "veryslow") % Defaults to "veryslow". Possible values: "ultrafast", "superfast", "veryfast", "faster", "fast", "medium", "slow", "slower", "veryslow", "placebo" % There is no reason to use placebo. I recommend "ultrafast" during development and "veryslow" for release. #(audioBitRate "128k") % Defaults to 128k \book { \bookOutputSuffix "Partitur-Video" \paper { #(set-paper-size "video") top-margin = 10\mm bottom-margin = 10\mm line-width = 190\mm left-margin = 12\mm page-top-space = 0\mm horizontal-shift = 0\mm ragged-bottom = ##f ragged-last-bottom = ##f print-page-number = ##f page-breaking = #ly:optimal-breaking system-count = 14 max-systems-per-page = 1 min-systems-per-page = 1 top-system-spacing = #'((basic-distance . 0) (minimum-distance . 7) (padding . 0) (stretchability . 0)) last-bottom-spacing = #'((basic-distance . 0) (minimum-distance . 8) (padding . 0) (stretchability . 0)) } % The title page. There must be exactly _one_ title page . \markup { \column { \vspace #0 %\fill-line { \fontsize #18.0 \override #'(font-name . "Black Jack" ) "Resignation" } \fill-line { \fontsize #18.0 "Resignation" } \vspace #2 \fill-line { \fontsize #5.0 "Composer: Hugo Wolf (1860-1903)" } \vspace #.4 \fill-line { \fontsize #5.0 "Poet: Joseph von Eichendorff (1788-1857) )" } \vspace #1.5 \fill-line { \fontsize #5.0 "Engraved by Knut Petersen using Lilypond 2.19.56" } %\vspace #0 %\fill-line{\center-column{ \epsfile #X #25 #"LilypondLogo.eps" }} } } \pageBreak % Start score on page 2 \score { \new ChoirStaff << \new Staff {\new Voice = sop {\globMus \tempo "MäÃig langsam" 4=63 \sopMusic}}\new Lyrics \with{}\lyricsto sop {\satWords} \new Staff {\new Voice = alt {\globMus \altMusic}}\new Lyrics \with{}\lyricsto alt {\satWords} \new Staff {\new Voice = ten {\globMus \tenMusic}}\new Lyrics \with{}\lyricsto ten {\satWords} \new Staff {\new Voice = bas {\globMus \basMusic}}\new Lyrics \with{}\lyricsto bas {\bWords} >> \layout{ \context { \Voice \consists "Ambitus_engraver" } \context{ \Staff \override VerticalAxisGroup #'staff-staff-spacing = #'((basic-distance . 0) (minimum-distance . 0) (padding . 3.0) (stretchability . 100)) } \context{ \Lyrics \override VerticalAxisGroup #'nonstaff-relatedstaff-spacing = #'((basic-distance . 0) (minimum-distance . 0) (padding . 1.0) (stretchability . 100)) \override VerticalAxisGroup #'nonstaff-unrelatedstaff-spacing = #'((basic-distance . 0) (minimum-distance . 0) (padding . 1.5) (stretchability . 100)) } } } } \pdfforvideo % This passes the name of the pdf to be used for video production to mkvideo % % Some definitions used for midi generation ... you probably want to change instrument names % and you might change or delete the volume overrides ... % #(define my-absolute-volume-alist '()) #(set! my-absolute-volume-alist (append '(("ff" . 1.00) '("f" . 0.90) ("mf" . 0.81) ("mp" . 0.73) ("p" . 0.66) ("pp" . 0.59)) my-absolute-volume-alist)) #(define-public (my-dynamic-absolute-volume s) (assoc-get s my-absolute-volume-alist)) panmidi = { \set Score.dynamicAbsoluteVolumeFunction = #my-dynamic-absolute-volume \set Staff.midiInstrument = #"pan flute" \set Staff.midiMinimumVolume = #0.00 \set Staff.midiMaximumVolume = #1.0 \set Staff.midiReverbLevel = #1.0 } pianomidi = { \set Score.dynamicAbsoluteVolumeFunction = #my-dynamic-absolute-volume \set Staff.midiInstrument = #"acoustic grand" \set Staff.midiMinimumVolume = #0.00 \set Staff.midiMaximumVolume = #0.65 \set Staff.midiReverbLevel = #1.0 } % Video 1: All voices played with a pan flute % % r1*5 \tempo 4 = 60 after \sopMusic adds some silence to the end of the midi file. % Without an event like \tempo silence at the end would be deleted, so we need it. \book{ \bookOutputSuffix "Video-Alle" \score { << \new Staff { \globMus \panmidi \set Staff.midiPanPosition = #-1.00 { \tempo 4=63 \sopMusic r1*5 \tempo 4 = 60}} \new Staff { \globMus \panmidi \set Staff.midiPanPosition = #-0.33 { \altMusic }} \new Staff { \globMus \panmidi \set Staff.midiPanPosition = #+0.33 { \tenMusic }} \new Staff { \globMus \panmidi \set Staff.midiPanPosition = #+1.00 { \basMusic }} >> \midi {} } } \midiforvideo % this passes the name of midi files to be used for video production to mkvideo % % Video 2 to 5 all use a low volume piano version of all voices in the background ... % pianoback = { << \new Staff { \globMus \pianomidi \set Staff.midiPanPosition = #-1.00 { \tempo 4=63 \sopMusic r1*5 \tempo 4 = 60}} \new Staff { \globMus \pianomidi \set Staff.midiPanPosition = #-0.33 { \altMusic }} \new Staff { \globMus \pianomidi \set Staff.midiPanPosition = #+0.33 { \tenMusic }} \new Staff { \globMus \pianomidi \set Staff.midiPanPosition = #+1.00 { \basMusic }} >> } % % ... and a higher volume pan flute for the emphasized voice % \book{ \bookOutputSuffix "Video-Alle-Grand" \score { \pianoback \midi {} }} \midiforvideo \book{ \bookOutputSuffix "Video-Sopran" \score { << \pianoback \new Staff { \globMus \panmidi \set Staff.midiPanPosition = #+0.00 { \sopMusic }} >> \midi {} }} \midiforvideo \book{ \bookOutputSuffix "Video-Alt" \score { << \pianoback \new Staff { \globMus \panmidi \set Staff.midiPanPosition = #+0.00 { \altMusic }} >> \midi {} }} \midiforvideo \book{ \bookOutputSuffix "Video-Tenor" \score { << \pianoback \new Staff { \globMus \panmidi \set Staff.midiPanPosition = #+0.00 { \tenMusic }} >> \midi {} }} \midiforvideo \book{ \bookOutputSuffix "Video-Bass" \score { << \pianoback \new Staff { \globMus \panmidi \set Staff.midiPanPosition = #+0.00 { \basMusic }} >> \midi {} }} \midiforvideo
_______________________________________________ lilypond-user mailing list lilypond-user@gnu.org https://lists.gnu.org/mailman/listinfo/lilypond-user