%D \module %D [ file=t-lilypond, %D version=2007.09.02, %D title=\CONTEXT\ User Modules, %D subtitle=LilyPond Connections (Music Typesetting), %D author={Christopher Creutzig, Henning Hraban Ramm, Mojka Miklavec}, %D date=\currentdate, %D copyright=Christopher Creutzig] %C %C This module licensed under the GNU GPL. %D This module serves to include LilyPond music directly in the %D \CONTEXT\ source, just as \METAPOST\ code can be. %D It should work from LilyPond version 2.8, but you should always use %D the latest stable version of LilyPond (this is tested with 2.10.29). %D %D {\bfa Complete list of options:} %D %D \starttabulate[|l|l|l|] %D \NC option\NC default\NC comment\NC\NR %D \HL %D \NC staffsize\NC 20\NC in pt \NC\NR %D \NC indent\NC 0pt\NC first line indent \NC\NR %D \NC time\NC yes\NC count time? (i.e. show time signature, set bars, split line) \NC\NR %D \NC clef\NC yes\NC show clef? \NC\NR %D \NC linewidth\NC \\localhsize\NC \NC\NR %D \NC betweensystemspace\NC 54pt\NC space between systems \NC\NR %D \NC height\NC \\textheight\NC \NR %D \NC align\NC ?\NC default depends on fragment=... \NC\NR %D \NC fragment\NC no\NC \NC\NR %D \NC barnumbers\NC no\NC show numbers of measures? \NC\NR %D \NC showempty\NC no\NC drop empty staves? \NC\NR %D \NC seriffont\NC "Century Schoolbook L"\NC font for e.g. lyrics \NC\NR %D \NC sansfont\NC "LMSans10"\NC font for e.g. chords \NC\NR %D \NC monofont\NC "Courier" \NC normally not used \NC\NR %D \stoptabulate %D %D TODO: Proper support for multipage results. %D %D TODO: LilyPond ---> \CONTEXT. %D %D As usual, we use a prefix for buffers, \type{\getparameters} etc.: \writestatus{loading}{LilyPond module} \startmodule[lilypond] \unprotect \def\??lily{lilypond-} %D Define the text snippets to be placed around fragments. %D Since LilyPond uses similar syntax to TeX, we must do some catcode fiddling. \def\lily!slash{/} \bgroup \catcode`\/=\@@escape /catcode`/\=/@@other /catcode`/#=/@@other /catcode`/<=/@@begingroup /catcode`/>=/@@endgroup /catcode`/{=/@@other /catcode`/}=/@@other /catcode`/%=/@@other /catcode`/-=/@@letter /gdef/lily!fragmentprefix< /string^^J /string^^J {/string^^J % ly snippet contents follows:/string^^J > /gdef/lily!fragmentsuffix /gdef/lily!prefix /gdef/lily!hash<#> /egroup \newdimen\lily!linewidth \newdimen\lily!vsize \newdimen\lily!indent \newdimen\lily!betweensystemspace \newif\iflily!align \newif\iflily!clef \newif\iflily!time \newif\iflily!barnumbers \newif\iflily!showempty \newcounter\lily!figures %D Again, as usual, there is a \type{\setuplilypond} command %D that accepts the same parameters as \type{\lilypond} and %D \type{\startlilypond} do in their optional argument. \def\setuplilypond{% \start\catcode`\#=\@@other% \dosingleempty\dosetuplilypond% } \def\dosetuplilypond[#1]{% \stop% restore \catcode`\# \getparameters[\??lily][#1]% } %D We set the following defaults: \setuplilypond [staffsize=20, indent=0pt, betweensystemspace=54pt, time=\v!yes, clef=\v!yes, align=?, % default depends on fragment=... fragment=\v!no, barnumbers=\v!no, showshowemptyempty=\v!no, seriffont="Century Schoolbook L", % LilyPond default font sansfont="LMSans10", monofont="Bitstream Vera Sans Mono", ] %D If you want to know which fonts of your system LilyPond can see %D with which names, try \type{lilypond -dshow-available-fonts any}. %D (The 3rd parameter is necessary, but can be anything.) %D There are a lot of restrictions, e.g. no fonts from the \TeX\ tree (don't know why), %D only one face per font file etc. %D \type{\startlilypond} is a multistage implementation, because %D end-of-line characters must be treated specially in the %D \type{\startlilypond}\textellipsis\type{\stoplilypond} range. \def\startlilypond{% \bgroup% \catcode`\#=\@@other% \dosingleempty\dostartlilypond% } \def\dostartlilypond[#1]{% \obeylines% \dodostartlilypond[{#1}]% } \long\def\dodostartlilypond[#1]#2\stoplilypond{% \egroup% from \startlilypond \bgroup% %D The default of the \type{linewidth} parameter is the local \type{\hsize}. \setlocalhsize \getparameters[\??lily][linewidth=\the\localhsize,height=\the\textheight,#1]% \lily!linewidth\dimexpr\getvalue{\??lily linewidth}\relax \lily!vsize\dimexpr\getvalue{\??lily height}\relax \lily!indent\dimexpr\getvalue{\??lily indent}\relax \lily!betweensystemspace\dimexpr\getvalue{\??lily betweensystemspace}\relax %D The default of \type{align} depends on whether we typeset a fragment: \@EAEAEA\doifelse\getvalue{\??lily align}{\v!yes}% \lily!aligntrue\lily!alignfalse \@EAEAEA\doif\getvalue{\??lily fragment}{\v!no}{% \@EAEAEA\doif\getvalue{\??lily align}? \lily!aligntrue }% \@EAEAEA\doifelse\getvalue{\??lily time}\v!yes \lily!timetrue\lily!timefalse \@EAEAEA\doifelse\getvalue{\??lily barnumbers}\v!yes \lily!barnumberstrue\lily!barnumbersfalse \@EAEAEA\doifelse\getvalue{\??lily showempty}\v!yes \lily!showemptytrue\lily!showemptyfalse \@EAEAEA\doifelse\getvalue{\??lily clef}\v!yes \lily!cleftrue\lily!cleffalse %D We are using a counter to keep the different LilyPond pieces %D separate. This allows to typeset them only once, during the %D first run. %D %D TODO: This won't work any longer once we pass the remaining %D vertical space to LilyPond. %\global\advance\lily!figures\plusone \doglobal\increment\lily!figures \edef\lily!filename{\bufferprefix lilypond-\lily!figures}%\the %\writestatus{buffering}{\lily!filename} %\startmode[*\v!first]% \def\obeyedlines{\string^^J}% \convertargument#2\to\ascii \expanded{% \setbuffer[lilypond-\lily!figures]%\the \lily!prefix \lily!hash(set-global-staff-size \getvalue{\??lily staffsize})\string^^J% \ifundefined{\??lily fragment}\else\lily!fragmentprefix\fi %% TODO: Option "packed" \ascii% \ifundefined{\??lily fragment}\else\lily!fragmentsuffix\fi }% expanded \endbuffer% %D %D Generating a PDF directly always creates a whole page, so we generate EPS first. %D %D If \type{\ifeof18} creates an error for you, your pdfe\TeX\ is too old. %D just change it to \type{\iftrue} then. %D (\type{\ifeof18} checks whether \type{\write18} is disabled.) %\def\LP{echo LILYPOND \lily!filename.tmp} %\def\PDF{echo PStoPDF \lily!filename.eps} \def\LP{texmfstart --ifchanged=\lily!filename.tmp --exec bin:lilypond -b eps -dno-gs-load-fonts -dinclude-eps-fonts \lily!filename.tmp} \def\PDF{texmfstart --ifchanged=\lily!filename.eps pstopdf \lily!filename.eps} %D The following line is needed for Lua\TeX, where buffers are kept in memory %D in contrast to other (older) flavours of \TeX\ where they're written to a %D file automatically. We have to require writing to a file explicitely %D with \type{\savebuffer}. \ifx\directlua\undefined \else \savebuffer[lilypond-\the\lily!figures]\fi %D %D If \type{\ifeof18} creates an error for you, your pdfetex is too old. %D just change it to \iftrue then. (\type{\ifeof18} checks whether \type{\write18} %D is disabled.) %D \ifeof18 %\writestatus{DEBUG-w18}{\LP}% \expanded{\installprogram{\LP}}% \doif\jobsuffix{pdf}{% \installprogram{\PDF}% }% \else %\writestatus{DEBUG-EXE}{\LP}% \executesystemcommand{\LP}% \doif\jobsuffix{pdf}{% \executesystemcommand{\PDF}% }% \fi %\stopmode% only first run \doifelse\jobsuffix{pdf} {\def\lily!img{\lily!filename .pdf}}% {\def\lily!img{\lily!filename .eps}}% %D %D TODO: Get the relevant dimension directly from LilyPond, %D to place the instrument name into the left margin for %D short snippets as well. %D %D If we are not in the middle of some text, we have to check %D whether LilyPond created an image that is wider than requested: %D It places the instrument names in the left margin. %D \ifvmode \getfiguredimensions[\lily!filename.pdf]% \leavevmode% \newdimen\FigWidth \FigWidth=\figurewidth \ifdim\FigWidth>\localhsize \!!dimena=\localhsize \advance\!!dimena by-\FigWidth \noindent\hskip\!!dimena \fi \fi \externalfigure[\lily!img]% \egroup% }% %D For short snippets, we define an inline alternative to %D our start/stop pair: \def\lilypond{\dosingleempty\dolilypond} \def\dolilypond[#1]#2{\startlilypond[#1]#2\stoplilypond} \stopmodule \protect \doifnotmode{demo}{\endinput} %D End of file \starttext \startbuffer[sample] \subject{Telemann, TWV 40:11} \startlilypond \relative c' { \set Staff.instrumentName = flute \key fis \minor \time 3/4 \partial 4 r8 fis'8 | fis4. cis8 a cis | fis, a cis fis a fis | b, d fis b d b | eis,, gis cis eis gis b, | a fis' gis, fis' cis eis | fis,4 r8 a' gis fis | e gis, a e' fis cis | d fis, gis b e d | cis4 \trill r8 cis b a | b dis e gis cis, b | a e' dis fis b, a | gis4 \trill r8 } \stoplilypond \stopbuffer The input \typebuffer[sample] is typeset as \getbuffer[sample] \type{\startlilypond} accepts options, as in\crlf \type{\startlilypond[staffsize=24, linewidth=14cm, indent=5cm, time=no, clef=no]}: \nobreak \startlilypond[staffsize=18,linewidth=14cm,indent=5cm,time=no,clef=no] \relative c' { \key fis \minor \time 3/4 \partial 4 r8 fis'8 | fis4. cis8 a cis | fis, a cis fis a fis | b, d fis b d b | eis,, gis cis eis gis b, | a fis' gis, fis' cis eis | fis,4 r8 a' gis fis | e gis, a e' fis cis | d fis, gis b e d | cis4 \trill r8 cis b a | b dis e gis cis, b | a e' dis fis b, a | gis4 \trill r8 } \stoplilypond It is also possible to mix text and music: \lower 8.2pt\hbox{\lilypond[fragment=true,staffsize=16,time=no]{g'}} is a g. (Seems like this still doesn't work...) TODO: The \type{\lower} in the example above should not be necessary. \stoptext