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 scoreHere'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 musicNeed 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