\NeedsTeXFormat{LaTeX2e}
\documentclass[10pt]{letter}
%
% It is assumed that lilypond 2.21 and a recent TeX distribution is used, e.g. TeX-Live 2017.
%
% Compile with with either
%
%    pdflatex --shell-escape sourcefile.ly
%    xelatex  --shell-escape sourcefile.ly
%    lualatex --shell-escape sourcefile.ly
%
% Then run ghostscript:
%
%    gs -dBATCH -dNOPAUSE -sDEVICE=pdfwrite -sOutputFile=final.pdf sourcefile.pdf
%
\usepackage{geometry}
\geometry{a4paper,noheadfoot,nomarginpar,left=3.5cm,right=2.5cm,top=2.5cm,bottom=2.5cm}

\usepackage[english,german]{babel}

\usepackage{ifluatex,ifxetex,ifpdf}
\def\isLuaTeX{\ifluatex 1\else 0\fi}
\def\isXeTeX{\ifxetex 1\else 0\fi}
\def\nocont{}
\if\isLuaTeX\isXeTeX
    \ifpdf
        \usepackage[T1]{fontenc}
        \usepackage[utf8]{inputenc}
    \else
        \def\nocont{
           \typeout{*******************************************}
           \typeout{* Use either pdflatex, lualatex or xelatex}
           \typeout{* to compile this file!}
           \typeout{*******************************************}
           \stop
        }
    \fi
\else
    \usepackage{fontspec}
    \defaultfontfeatures{Ligatures=TeX}
    \setmainfont{cmunrm.otf}[BoldFont=cmunbx.otf,ItalicFont=cmunti.otf,BoldItalicFont=cmunbi.otf]
    \setsansfont{cmunss.otf}[BoldFont=cmunsx.otf,ItalicFont=cmunsi.otf,BoldItalicFont=cmunso.otf]
    \setmonofont{cmuntt.otf}[BoldFont=cmuntb.otf,ItalicFont=cmunst.otf,BoldItalicFont=cmuntx.otf]
\fi
\nocont
\usepackage{pdftexcmds}
\ifxetex \let\pdfmdfivesum\mdfivesum \fi
\ifluatex \makeatletter \let\pdfmdfivesum\pdf@mdfivesum \makeatother \fi

\usepackage{environ}
\usepackage{graphicx}
\usepackage{shellesc}

\def\space{ }
\def\tmpFileContent{}
\def\tmpNamePrefix{\jobname .tly}
\def\tmpNameFull{\tmpNamePrefix .ly}
\def\tmpNameHead{\tmpNamePrefix -head.ly}
\def\tmpNamePaper{\tmpNamePrefix -paper.ly}
\def\tmpNamePdf{\tmpNamePrefix .pdf }
\def\tmpNameTail{\tmpNamePrefix -tail.ly}

\def\lilycommand{lilypond -dbackend=eps }

\def\lilyversion{2.18.2} 
\def\intersystemcommand{\vskip\parskip}

\newwrite\tmpFileMain    \newwrite\tmpFileHead    \newwrite\tmpFileTail
\newwrite\tmpFilePaper   \newread\fragcountfile
\newcount\fragcount      \newcount\fragpagecount  \newcount\fragpagenum


{
  \catcode`|=0 \catcode`[=1 \catcode`]=2 \catcode`\#=12
  \catcode`\{=12 \catcode`\}=12 \catcode`\\=12
  |gdef|eohead[\end{lilyhead}]
  |gdef|eofrag[\end{lilyfrag}]
  |gdef|eotail[\end{lilytail}]
  |gdef|hashtag[#]
  |gdef|escape[\]
  |gdef|definepaper[\definepaper]
]

{
  \obeylines
  \gdef\doline#1
  {
    \def\oneline{#1}
    \ifx\oneline\eohead\def\next{\end{lilyhead}}\else
    \ifx\oneline\eofrag\def\next{\end{lilyfrag}}\else
    \ifx\oneline\eotail\def\next{\end{lilytail}}\else 
    \ifx\oneline\definepaper\immediate\write\tmpFile{\escape include "\tmpNamePaper"}\let\next\doline
    \else
    \immediate\write\tmpFile{\unexpanded\expandafter{\oneline}}
    \edef\tmpFileContent{\unexpanded\expandafter{\tmpFileContent}
      \unexpanded\expandafter{\oneline}}
    \let\next\doline
    \fi\fi\fi\fi\next%
  }
}

\makeatletter


\newenvironment{lilyfrag}[2]{
  \global\advance\fragcount by 1
  \edef\tmpFileContent{}
  \immediate\openout\tmpFileMain=\tmpNameFull
  \gdef\tmpFile{\tmpFileMain}
  \immediate\write\tmpFileMain{\escape version "\lilyversion"}
  \immediate\write\tmpFileMain{\escape include "\tmpNameHead"}
  \immediate\openout\tmpFilePaper=\tmpNamePaper
  \immediate\write\tmpFilePaper{\hashtag(set!
     paper-alist (cons '("mySize" . (cons (* #1) (* #2))) paper-alist))}
  \immediate\closeout\tmpFilePaper
  \let\do=\@makeother\dospecials\obeylines\doline
}{
  \def\tmpFragPrefix{\pdfmdfivesum{\unexpanded\expandafter{\tmpFileContent}}}
  \def\tmpFragName{\tmpFragPrefix\space}
  \IfFileExists{./\tmpFragPrefix-1.pdf}{}{
    \immediate\write\tmpFileMain{\escape include "\tmpNameTail"}
    \immediate\closeout\tmpFileMain
    \immediate\write18{\lilycommand -o \tmpFragName \tmpNameFull}
  }
  \openin\fragcountfile=\tmpFragPrefix-systems.count
  \read\fragcountfile to \fragpagecount
  \closein\fragcountfile
  \fragpagenum=1
  \begin{center}
  \loop
    \IfFileExists{./\tmpFragPrefix-\the\fragpagenum.pdf}{}{
       \def\nocont{
          \typeout{*************************************************}
          \typeout{* Something went wrong. Probably lilypond failed}
          \typeout{* or you tried to compile this file without the}
          \typeout{* --shell-escape command line parameter!}
          \typeout{*************************************************}
          \stop
       }
    }
    \nocont
    \hbox{\vbox{\includegraphics{\tmpFragPrefix-\the\fragpagenum.pdf}}}
    \ifnum\fragpagenum<\fragpagecount\intersystemcommand\fi
    \advance\fragpagenum by 1 \unless\ifnum\fragpagenum>\fragpagecount
  \repeat
  \end{center}
}

\newenvironment{lilyhead}{
  \immediate\openout\tmpFileHead=\tmpNameHead
  \gdef\tmpFile{\tmpFileHead}
  \let\do=\@makeother\dospecials\obeylines\doline
}{
  \immediate\closeout\tmpFileHead
}

\newenvironment{lilytail}{
  \immediate\openout\tmpFileTail=\tmpNameTail
  \gdef\tmpFile{\tmpFileTail}
  \let\do=\@makeother\dospecials\obeylines\doline
}{
  \immediate\closeout\tmpFileTail
}

\makeatother

\usepackage{verbatim}
\begin{document}
\selectlanguage{english}
\pagestyle{empty}

This code demonstrates how it is possible to include lilypond scores in a document
intended to be translated by pdflatex, xelatex or lualatex.

Someone who wants to include one lilypond score, probably often wants to include more
than one score. Because of that the three environments lilyhead, lilyfrag and
lilytail are implemented.

Put code at the top of the scores that is common to all of them in a {\bfseries lilyhead}
environment. Everything in a lilyhead environment is written to \verb!\tmpFileHead!.
A lilyhead environment might be empty, but at least an empty lilyhead environment has
to be defined before the first lilyfrag environment is used.

Put code at the bottom of the scores that is common to all of them in a {\bfseries lilytail}
environment. Everything in a lilytail environment is written to \verb!\tmpFileTail!.
A lilytail environment might be empty, but at least an empty lilytail environment has
to be defined before the first lilyfrag environment is used.

Put the rest of the scores in {\bfseries lilyfrag} environments.

The lilyfrag environment will put a lilypond \verb!\version! statement
and an instruction to include \verb!\tmpFileHead! at the top of \verb!\tmpFileMain!.
The version string to be used should be defined in \verb!\lilyversion!.
After that everything in the lilyfrag environment ist written to \verb!\tmpFileMain! and
an instruction to read \verb!\tmpFileTail! is appended.

The first argument of the lilyfrag environment is the paper width,
the second argument is the paper height. In both arguments there must be white space
between the number and the unit. The lilyfrag environment takes those
arguments and constructs a scheme command that sets the paper-alist
to an alists that contains the paper size \verb!mySize! defined accordingly.
That scheme command is written to a temporary file \verb!\tmpFilePaper!.

A line in one of the environments that contains nothing
but \verb!\definepaper! (nothing really means nothing, no comments, no whitespace!) will
be replaced with a lilypond command to read the file \verb!\tmpFilePaper!. You probably
want to include the instruction \verb!\definepaper! in the lilyhead
environment. 

After \verb!\tmpFileMain! is closed, lilypond is executed with the command line defined in 
\verb!\lilycommand!, the PDFs are renamed and \verb!\includegraphics! is used to read those
PDFs.

If the lilyfrag environment produces more than one sysytem / pdf, \verb!\intersystemcommand!
is executed between those pdfs. Typically you want to introduce some vertical glue.

The source file is expected to be utf8-encoded, and everything in one of
the three environments defined in this file is passed to lilypond. It is
not necessary that the tex engine is set up to handle the glyphs passed
to lilypond. 

The code is intended to be used with either lualatex, xelatex or pdflatex.

Both lualatex and xelatex have some limitations:

Lualatex will fail if it reaches the soft limit of file descriptors. Raising that
limit should work, but don't expect that raising the limit beyond 1024
will help as a library bug might be exposed.

Xelatex  will fail if you try to include more than 5000 pdfs. Expect this known
bug to be fixed with TeX-Live 2018.

Pdflatex showed no problems and a lot of free memory after passing a test with
7500 scores that produced 15000 pdfs.

Here is an example:
\newpage
\begin{verbatim}
\def\lilyversion{2.18.2} 
\def\intersystemcommand{\vskip\parskip}

\begin{lilyhead}
\definepaper
    \paper {
        #(set-paper-size "mySize")
        left-margin          = 0\cm     top-margin           = 0\cm
        bottom-margin        = 0\cm     line-width           = \paper-width
        indent               = 0        max-systems-per-page = #1
        ragged-right         = ##f      ragged-bottom        = ##t
        ragged-last-bottom   = ##t      annotate-spacing     = ##f
        print-page-number    = ##f      oddHeaderMarkup      = ##f
        evenHeaderMarkup     = ##f      oddFooterMarkup      = ##f
        evenFooterMarkup     = ##f      bookTitleMarkup      = ##f
        scoreTitleMarkup     = ##f }
    \header { tagline = ##f }
    \score {
\end{lilyhead}

\begin{lilytail}
    \layout{
        \context { \Score \omit BarNumber }
        \override Lyrics.LyricText  #'font-name = #"Linux Libertine O,serif"
        \override StanzaNumber.font-name = #"Linux Libertine O,serif"
        \override LyricText.font-size = #1
        \override StanzaNumber.font-size = #1 } }    
\end{lilytail}

Fragment 1
\begin{lilyfrag}{12 cm}{18 cm}
    \relative { c' d e f \break g a b c \break c b a g \break f e d c }
    \addlyrics{ c' d' e' f' g' a' b' c'' c'' b' a' g' f' e' d' c' }
\end{lilyfrag}

Fragment 2
\begin{lilyfrag}{12 cm}{18 cm}
   \relative { c'2 d e f g f e }   \addlyrics { ... }
\end{lilyfrag}

Fragment 3
\begin{lilyfrag}{12 cm}{18 cm}
   \relative { c'2 d e f g f e }   \addlyrics { ... }
\end{lilyfrag}

Fragment 4
\begin{lilyfrag}{12 cm}{18 cm}
   \relative { c'2 d e f g f e }
   \addlyrics { à vo -- cê uma can -- ção legal }
\end{lilyfrag}
\end{verbatim}

\newpage

\begin{lilyhead}
#(define default-toplevel-book-handler
  print-book-with-defaults-as-systems )

#(define toplevel-book-handler
  (lambda ( . rest)
  (set! output-empty-score-list #f)
  (apply print-book-with-defaults rest)))

#(define toplevel-music-handler
  (lambda ( . rest)
   (apply collect-music-for-book rest)))

#(define toplevel-score-handler
  (lambda ( . rest)
   (apply collect-scores-for-book rest)))

#(define toplevel-text-handler
  (lambda ( . rest)
   (apply collect-scores-for-book rest)))
\end{lilyhead}


This is the result of the code printed on the previous page:

\def\lilyversion{2.18.2} 
\def\intersystemcommand{\vskip\parskip}

\begin{lilyhead}
\definepaper
\paper {
        #(set-paper-size "mySize")
        left-margin          = 0\cm     top-margin           = 0\cm
        bottom-margin        = 0\cm     line-width           = \paper-width
        indent               = 0        max-systems-per-page = #1
        ragged-right         = ##f      ragged-bottom        = ##t
        ragged-last-bottom   = ##t      annotate-spacing     = ##f
        print-page-number    = ##f      oddHeaderMarkup      = ##f
        evenHeaderMarkup     = ##f      oddFooterMarkup      = ##f
        evenFooterMarkup     = ##f      bookTitleMarkup      = ##f
        scoreTitleMarkup     = ##f }
    \header { tagline = ##f }
    \score {
\end{lilyhead}

\begin{lilytail}
    \layout{
        \context { \Score \omit BarNumber }
        \override Lyrics.LyricText  #'font-name = #"Linux Libertine O,serif"
        \override StanzaNumber.font-name = #"Linux Libertine O,serif"
        \override LyricText.font-size = #1
        \override StanzaNumber.font-size = #1 } }    
\end{lilytail}

Fragment 1
\begin{lilyfrag}{12 cm}{18 cm}
    \relative { c' d e f \break g a b c \break c b a g \break f e d c }
    \addlyrics{ c' d' e' f' g' a' b' c'' c'' b' a' g' f' e' d' c' }
\end{lilyfrag}

Fragment 2
\begin{lilyfrag}{12 cm}{18 cm}
   \relative { c'2 d e f g f e }
   \addlyrics { זה כיף סתם לשמוע איך תנצח קרפד עץ טוב בגן. }
\end{lilyfrag}

Fragment 3
\begin{lilyfrag}{12 cm}{18 cm}
   \relative { c'2 d e f g f e }
   \addlyrics { Жълтата дюля беше щастлива, че пухът, който }
\end{lilyfrag}

Fragment 4
\begin{lilyfrag}{12 cm}{18 cm}
   \relative { c'2 d e f g f e }
   \addlyrics { à vo -- cê uma can -- ção legal }
\end{lilyfrag}



\end{document}
