LilyPond

From Wiki
Revision as of 23:09, 20 January 2013 by Hraban (talk | contribs) (complete overhaul; deleted documentation for old module)
Jump to navigation Jump to search

< Graphics | Using Graphics >

LilyPond is a great music engraver, and you can include LilyPond in ConTeXt source using the filter module with some setup.

Simple Filter Setup

This works with ConTeXt MkII and MkIV, but takes only the first page of multi-pages scores, and you must create the folder "lilytemp" manually:

\def\readPDFfile#1{\externalfigure[#1]}

\usemodule[filter]
\defineexternalfilter[lilypond]
	[continue=yes,
	readcommand=\readPDFfile,
	directory=lilytemp/, % directory for LilyPond's files
	output={\externalfilterbasefile.pdf},
	filtercommand={lilypond -dbackend=eps -dno-gs-load-fonts -dinclude-eps-fonts -ddelete-intermediate-files -o"lilytemp/\externalfilterbasefile" "\externalfilterinputfile"}]

Multi Page Filter Setup

This uses Lua and therefore only works with ConTeXt MkIV. It includes all pages of multi-page scores. It doesn’t look into the complete (multi-page) PDF, but reads a "-system.count" auxiliary file written by LilyPond that contains the number of systems (pages) and includes the single-system PDFs.

\def\ParseLilypondFile#1% #1 is the name of the output file
  {\ctxlua{thirddata.parselilypondfile("#1")}}

\startluacode
 thirddata = thirddata or {}
 
 -- create temp folder if missing
 if not lfs.isdir('lilytemp') then
   lfs.mkdir('lilytemp')
 end
 
 function thirddata.parselilypondfile(name)
   -- include all systems (pages)
   -- name is like lilytemp/mainfile-temp-lilypond-21.pdf
   logs.report("LILYPOND name='" .. name .. "'")
   syco = 0
   for ts in io.lines(string.gsub(name, '%.pdf$', '-systems.count')) do
     syco = ts*1
   end
   
   for nr = 1, syco do
     logs.report("LILYPOND including system no." .. nr)
     context("\\externalfigure[" .. string.gsub(name, '%.pdf$', '-' .. nr) .. "]")
   end
 end
\stopluacode

\usemodule[filter]
\defineexternalfilter[lilypond]
	[continue=yes,
	readcommand=\ParseLilypondFile,
	directory=lilytemp/,
	output={\externalfilterbasefile.pdf},
	filtercommand={lilypond -dbackend=eps -dinclude-eps-fonts -dno-gs-load-fonts -o"lilytemp/\externalfilterbasefile" "\externalfilterinputfile"}]


LilyPond Settings

Collect your LilyPond settings in a .ly file, put it in your lilytemp directory and include it from within your lilypond block like this:

\startlilypond
\include "mysettings.ly"
...
\stoplilypond

Named Buffers

Normally, your LilyPond snippets just get a running number. If you re-order your scores, each one gets re-rendered.

You might want to add [name=\currentcomponent] (or name=mymusic) to \startlilypond to avoid unnecessary re-rendering.

Example

(TODO: This is old and might contain deprecated or non-working code. Unchecked.)

Here's an example of placing score snippets in the body of the text, with fonts in the score & body matching:

\unprotect

\usemodule[filter]

\traceexternalfilters

\defineexternalfilter
  [lilypond]
  [\c!output=\externalfilterbasefile.pdf,
   \c!filtercommand=\lilypondcommand,
   \c!continue=\v!yes,
   \c!readcommand=\readlilypondoutput,
   %\c!directory=output,
  ]

% frame=on is for testing
\def\readlilypondoutput#1{\setupfloats[location=right,frame=off]\placefigure[]{From \sc{http://lsr.dsi.unimi.it/LSR/Search?q=piano}}{\externalfigure[#1]}}

\def\lilypondcommand%
	{lilypond -dbackend=eps -dno-gs-load-fonts -dinclude-eps-fonts \externalfilterinputfile}
\protect

\setuplayout[textwidth=6in] % matches line-width below
\usetypescript[palatino]
\setupbodyfont[palatino,13pt]

\starttext

\input zapf 

\startlilypond
\layout{
  indent=0\mm
  ragged-right = ##f
}
\paper  {
	myStaffSize = #20
	#(define fonts
	  (make-pango-font-tree "palatino"
		"palatino"
		"palatino"
               (/ myStaffSize 20))) 
  line-width=6\in
  oddFooterMarkup=##f
  oddHeaderMarkup=##f
  bookTitleMarkup = ##f
  scoreTitleMarkup = ##f
 }
global = {
  \key c \major
  \time 4/4
}

sopMusic = \relative c'' {
  c4 c c8[( b)] c4
}
sopWords = \lyricmode {
  hi hi hi hi
}

altoMusic = \relative c' {
  e4 f d e
}
altoWords =\lyricmode {
  ha ha ha ha
}

tenorMusic = \relative c' {
  g4 a f g
}
tenorWords = \lyricmode {
  hu hu hu hu
}

bassMusic = \relative c {
  c4 c g c
}
bassWords = \lyricmode {
  ho ho ho hø
}

\score {
  <<
    \new ChoirStaff <<
      \new Lyrics = "sopranos"
      \new Staff = "women" <<
        \new Voice = "sopranos" { \voiceOne << \global \sopMusic >> }
        \new Voice = "altos" { \voiceTwo << \global \altoMusic >> }
      >>
      \new Lyrics = "altos"
      \new Lyrics = "tenors"
      \new Staff = "men" <<
        \clef bass
        \new Voice = "tenors" { \voiceOne << \global \tenorMusic >> }
        \new Voice = "basses" { \voiceTwo << \global \bassMusic >> }
      >>
      \new Lyrics = "basses"
      \context Lyrics = "sopranos" \lyricsto "sopranos" \sopWords
      \context Lyrics = "altos" \lyricsto "altos" \altoWords
      \context Lyrics = "tenors" \lyricsto "tenors" \tenorWords
      \context Lyrics = "basses" \lyricsto "basses" \bassWords
    >>
    \new PianoStaff <<
      \new Staff <<
        \set Staff.printPartCombineTexts = ##f
        \partcombine
        << \global \sopMusic >>
        << \global \altoMusic >>
      >>
      \new Staff <<
        \clef bass
        \set Staff.printPartCombineTexts = ##f
        \partcombine
        << \global \tenorMusic >>
        << \global \bassMusic >>
      >>
    >>
  >>
}
\stoplilypond
\input zapf
\stoptext

Deprecation

The old LilyPond module (t-lilypond) doesn't work any more with recent versions of ConTeXt, therefore we removed its documentation here.