Lilypond Polytempo Notation

Here's how to get polytempo engraving and MIDI rendering working correctly in Lilypond. There's some info on the web, but it took me a while to figure out how to put everything together. As such, I'm hoping this can be helpful for others.

As of writing, I'm quite new to LilyPond, and I only figured this out through lots of trial and error. So please pardon if anything is unidiomatic or otherwise bad, and let me know if you have any suggestions!

(1) Set up the score

Here's the basic starting template for polytempo projects in Lilypond:

\version "2.24.3"

\score {

  % music will go here

	\layout {
		\enablePolymeter
		\context {
			\Score
			forbidBreakBetweenBarLines = ##f
			\remove Metronome_mark_engraver
		}
		\context {
			\Voice
			\consists Metronome_mark_engraver
			\remove Forbid_line_break_engraver
		}
  }

	\midi {
		\context {
			\Score
			\remove Tempo_performer
			\remove Time_signature_performer
		}
	}
}

I found this template through trial and error, so I'm honestly not exactly sure why it works. That said, it prevents Lilypond from automatically doing some stuff that we need to manually handle, and allows measures to take up multiple systems.

(2) Input the music

Need to have something to work with. For this example, the top part will have one bar at 45bpm and another at 90bpm, and the bottom part will have two bars at 60bpm.

\version "2.24.3"

\score {

<<
  \new Staff {
    \tempo 4 = 45
    a'4 b'4 c''4 e''4 |
    \tempo 4 = 90
    d''4 c''4 b'4 a'4 |
  }
  \new Staff {
    \tempo 4 = 60
    a'4 b'4 c''4 e''4 |
    d''4 c''4 b'4 a'4 |
  }
>>

	\layout {
		\enablePolymeter
		\context {
			\Score
			forbidBreakBetweenBarLines = ##f
			\remove Metronome_mark_engraver
		}
		\context {
			\Voice
			\consists Metronome_mark_engraver
			\remove Forbid_line_break_engraver
		}
	}

	\midi {
		\context {
			\Score
			\remove Tempo_performer
			\remove Time_signature_performer
		}
	}
}
(3) Manually handle bar lines

If we let Lilypond try to handle bar lines, it will place a bar line in every part whenever there's one in the first part. As such, we need to instead handle bar lines manually.

We do this by adding \set Staff.measureBarType = "" in each staff. We then put \bar "|" wherever we want a barline.

\version "2.24.3"

\score {

<<
  \new Staff {
    \set Staff.measureBarType = ""
    \tempo 4 = 45
    a'4 b'4 c''4 e''4 \bar "|"
    \tempo 4 = 90
    d''4 c''4 b'4 a'4 \bar "|"
  }
  \new Staff {
    \set Staff.measureBarType = ""
    \tempo 4 = 60
    a'4 b'4 c''4 e''4 \bar "|"
    d''4 c''4 b'4 a'4 \bar "|"
  }
>>

	\layout {
		\enablePolymeter
		\context {
			\Score
			forbidBreakBetweenBarLines = ##f
			\remove Metronome_mark_engraver
		}
		\context {
			\Voice
			\consists Metronome_mark_engraver
			\remove Forbid_line_break_engraver
		}
	}

	\midi {
		\context {
			\Score
			\remove Tempo_performer
			\remove Time_signature_performer
		}
	}
}
(4) Scale durations according to the tempo

Here's where we actually make the polytempo stuff happen. We use Lilypond's \scaleDurations to scale the duration of each tempo mark's section. The amount we need to scale by is 100/bpm (any other number can be used besides 100, as long as it is consistent). \scaleDurations accepts a fraction, so this is pretty easy:

\version "2.24.3"

\score {

<<
  \new Staff {
    \set Staff.measureBarType = ""
    \tempo 4 = 45
    \scaleDurations 100/45 {a'4 b'4 c''4 e''4 \bar "|"}
    \tempo 4 = 90
    \scaleDurations 100/90 { d''4 c''4 b'4 a'4 \bar "|" }
  }
  \new Staff {
    \set Staff.measureBarType = ""
    \tempo 4 = 60
    \scaleDurations 100/60 {
      a'4 b'4 c''4 e''4 \bar "|"
      d''4 c''4 b'4 a'4 \bar "|"
    }
  }
>>

	\layout {
		\enablePolymeter
		\context {
			\Score
			forbidBreakBetweenBarLines = ##f
			\remove Metronome_mark_engraver
		}
		\context {
			\Voice
			\consists Metronome_mark_engraver
			\remove Forbid_line_break_engraver
		}
	}

	\midi {
		\context {
			\Score
			\remove Tempo_performer
			\remove Time_signature_performer
		}
	}
}

Note that if you have fractional or decimal bpms, you'll need to convert them into an improper fraction first. When I needed to do this, I just plugged 100/bpm into WolframAlpha, so it's not too bad.

(5) That's it!

Now Lilypond should properly generate a polytempo score and MIDI! Note that to have MIDI playback at the right speed, set the BPM in your sequencer to 100 (or whatever you used as the numerator for the scaleDurations fractions.)

The outputted score of this example can be found here: example.pdf. Here's the MIDI-generated audio:

Final thoughts

Firstly, I want to point out that Lilypond does not support fractional or decimal tempo marks by default. Here's a custom function I used to get them, at least defined for quarter notes:

\version "2.24.3"

quarterTempoManual = #(define-scheme-function
(bpm)
(string?)
#{
\tempo \markup {
	\concat {
		\smaller \general-align #Y #DOWN \note{4} #1
	" = "
	$bpm
	}
}
#}
)

Hopefully this is useful. As always, please let me know if there's anything I should clarify. Thanks for reading.

updated 2024-06-03
All content copyright (c) Dmitri Volkov 2024 unless otherwise noted.