[Tex/LaTex] Stretching vertical space to evenly fit a part of the document within minimal number of pages

lilypondmusicspacing

I typeset a book containing musical pieces using LaTeX and LilyPond (using lilypond-book). Each piece starts in a new page, and can be from less than a single page up to several pages long.

I want each piece to fill the required number of pages fully, so no space is left in the bottom part of the last page of the piece and the staves in all pages are evenly spaced. This can be achieved in LilyPond by setting ragged-last-bottom to ##f. Here is a simple example (music.ly):

#(set-global-staff-size 32)

\paper {
  paper-width = 18.5\cm
  ragged-last-bottom = ##f
}

\header{
  tagline = ##f
}

{
  c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c
  c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c
  c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c
  c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c
  c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c
}

This will produce this output:

Page 1/2:
Page 1/2 of good output

Page 2/2:
Page 2/2 of good output

Now, when I try to use this in LaTeX, it doesn’t work, since lilypond-book splits the LilyPond output into .eps files each containing a single line and these files are included one after another by the generated .tex file.

So, this LaTeX file produces an output which does not fill the pages fully with evenly spaced staves (as you can easily see by looking on the last page):

\documentclass[a4paper]{article}
\usepackage{geometry}

\begin{document}

hello world

\lilypondfile{music.ly}

\end{document}

Page 1/3:
Page 1/3 of bad output

Page 2/3:
Page 2/3 of bad output

Page 3/3:
Page 3/3 of bad output

So my question is simple: how do I make LaTeX behave like LilyPond does with ragged-last-bottom set to ##f?

Thank you very much! ☺

Best Answer

Interesting problem! Ultimately, lots of figuring out and legwork, but the solution ends up being very simple.

Thanks for introducing me to lillypond—cool stuff.

I'm still a bit confused because I've only been using it for about 5 minutes, but here's what I found.

You make this file, I called mine lillypond.ly:

#(set-global-staff-size 32)

\paper {
  paper-width = 18.5\cm
  ragged-last-bottom = ##f
}

\header{
  tagline = ##f
}

{
  c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c
  c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c
  c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c
  c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c
  c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c c
}

I took this straight from the your question.

Also straight from the your question is this file, I called mine lillypondtex.lytex (The .lytex extension is important and was difficult to figure out.)

\documentclass[a4paper]{article}
\usepackage{geometry}

\begin{document}

hello world

\lilypondfile{lillypond1.ly}

\end{document}

This file gets compiled with the command Applications/LilyPond.app/Contents/Resources/bin/lilypond-book --output=out --pdf lillypondtex.lytex at least, if you're on a mac and too lazy to follow the installation instructions. On a normal installation I think this command would be just lilypond-book --output=out --pdf lillypondtex.lytex.

That command generates a new directory, called out, which contains a directory called 5a (important later) and the files:

lillypondtex.dep
lillypondtex.tex
snippet-map--9077002354240704700.ly
snippet-names--9077002354240704700.ly

Now we're getting somewhere, finally an extension I know and love!

Running pdflatex on lillypondtex.tex gives the same output you saw and didn't like.

The lillypondtex.tex file contains this:

\documentclass[a4paper]{article}
\usepackage{geometry}

\usepackage{graphics}
\begin{document}

hello world

{%
\parindent 0pt
\noindent
\ifx\preLilyPondExample \undefined
\else
  \expandafter\preLilyPondExample
\fi
\def\lilypondbook{}%
\input{5a/lily-66b633c5-systems.tex}
\ifx\postLilyPondExample \undefined
\else
  \expandafter\postLilyPondExample
\fi
}

\end{document}

Still a little obfuscated, but the line \input{5a/lily-66b633c5-systems.tex} is the key.

Now, going into the 5a directory, we have the file called lily-66b633c5-systems.tex which is finally the layout code for the document.

\includegraphics{5a/lily-66b633c5-1}%
\ifx\betweenLilyPondSystem \undefined
  \linebreak
\else
  \expandafter\betweenLilyPondSystem{1}%
\fi
\includegraphics{5a/lily-66b633c5-2}%
\ifx\betweenLilyPondSystem \undefined
  \linebreak
\else
  \expandafter\betweenLilyPondSystem{2}%
\fi
\includegraphics{5a/lily-66b633c5-3}%
\ifx\betweenLilyPondSystem \undefined
  \linebreak
\else
  \expandafter\betweenLilyPondSystem{3}%
\fi
\includegraphics{5a/lily-66b633c5-4}%
\ifx\betweenLilyPondSystem \undefined
  \linebreak
\else
  \expandafter\betweenLilyPondSystem{4}%
\fi
\includegraphics{5a/lily-66b633c5-5}%
\ifx\betweenLilyPondSystem \undefined
  \linebreak
\else
  \expandafter\betweenLilyPondSystem{5}%
\fi
\includegraphics{5a/lily-66b633c5-6}%
\ifx\betweenLilyPondSystem \undefined
  \linebreak
\else
  \expandafter\betweenLilyPondSystem{6}%
\fi
\includegraphics{5a/lily-66b633c5-7}%
\ifx\betweenLilyPondSystem \undefined
  \linebreak
\else
  \expandafter\betweenLilyPondSystem{7}%
\fi
\includegraphics{5a/lily-66b633c5-8}%
\ifx\betweenLilyPondSystem \undefined
  \linebreak
\else
  \expandafter\betweenLilyPondSystem{8}%
\fi
\includegraphics{5a/lily-66b633c5-9}%
\ifx\betweenLilyPondSystem \undefined
  \linebreak
\else
  \expandafter\betweenLilyPondSystem{9}%
\fi
\includegraphics{5a/lily-66b633c5-10}%
\ifx\betweenLilyPondSystem \undefined
  \linebreak
\else
  \expandafter\betweenLilyPondSystem{10}%
\fi
\includegraphics{5a/lily-66b633c5-11}%
\ifx\betweenLilyPondSystem \undefined
  \linebreak
\else
  \expandafter\betweenLilyPondSystem{11}%
\fi
\includegraphics{5a/lily-66b633c5-12}%
\ifx\betweenLilyPondSystem \undefined
  \linebreak
\else
  \expandafter\betweenLilyPondSystem{12}%
\fi
\includegraphics{5a/lily-66b633c5-13}%
\ifx\betweenLilyPondSystem \undefined
  \linebreak
\else
  \expandafter\betweenLilyPondSystem{13}%
\fi
\includegraphics{5a/lily-66b633c5-14}%
% eof

These \linebreak commands are the problem, that's why LaTeX is treating the music as a single paragraph and not spreading it out evenly.

Any changes made here will effect the output of lillypond.tex. From here, I'm sure there are more experienced people here who can tweak this further than I can.


However, a couple simple solutions:

Simply find-replacing all cases of \linebreak with \par will allow \flushbottom to be used as expected in lillypond.tex. output:

enter image description here

This fixes spacing between all the lines and text. Making each line of music a paragraph is the solution I would choose if I were writing a book using this, as it would work with \flushbottom and flow around text well. Also, at this point, David Carlisle's asnwer of pasting \setlength\parskip{\fill} into the lillypond.tex file will work as he intended.

Another option is to replace each \linebreak with \vfill, which gets us closer to OP's desired outcome by filling the full last page.

From here it's just a matter of shrinking the margins to make them similar to lillypond's output. A margin of .75" top and bottom gives this output:

enter image description here

Even spacing, pages fully filled, I believe this is what you're asking for.

Final lillypond.tex file:

\documentclass[a4paper]{article}
\usepackage[margin=.75in]{geometry}

\usepackage{graphics}
\begin{document}
\flushbottom

\centering
hello world

{%
\parindent 0pt
\noindent
\ifx\preLilyPondExample \undefined
\else
  \expandafter\preLilyPondExample
\fi
\def\lilypondbook{}%
\input{5a/lily-66b633c5-systems.tex}
\ifx\postLilyPondExample \undefined
\else
  \expandafter\postLilyPondExample
\fi
}

\end{document}

Another option I just thought of is to use \pagebreaks in conjunction with \vfill to explicitly declare how many lines to show per page.


If you want default Article margins:

How to space out lines so they're evenly distributed with article class default margins: Use \par between the lines of music and then define \parskip like this:

\setlength\parskip{26pt plus 36pt minus 0pt}

This tells LaTeX that each line must have 26pt in between, and it's allowed to satisfy \flushbottom by stretching each line by 36pt but not allowed to compress the lines closer together.

Here's the result:

enter image description here

LaTeX breaks it up into two pages of five lines and one page of four lines.

Here's the code I used to make it:

\documentclass[a4paper]{article}
\usepackage[]{geometry}

\usepackage{graphics}
\begin{document}
\flushbottom

hello world

{%
\parindent 0pt
\noindent
\setlength\parskip{26pt plus 36pt minus 0pt}
\ifx\preLilyPondExample \undefined
\else
  \expandafter\preLilyPondExample
\fi
\def\lilypondbook{}%
\input{5a/lily-66b633c5-systems.tex}
\ifx\postLilyPondExample \undefined
\else
  \expandafter\postLilyPondExample
\fi
}

\end{document}
Related Question