DEV Community


Let It Snow!

mikesol profile image Mike Solomon Originally published at ・5 min read

I've been arranging a lot of things over the past two years as the CEO of Meeshkan — meetups, obligatory insurances, flights, pizza deliveries. However, one thing I haven't gotten the chance to arrange much is music. Until now! This holiday season, I took the time to make a six-voice arrangement of Let It Snow! by Sammy Cahn and Jule Styne. I have open-sourced the arrangement for folks to sing as they go caroling. In addition to a PDF, this project contains the LilyPond markdown and the small hack I wrote to get LilyPond to write swing rhythms correctly in the MIDI.

In this article, I'll discuss two facets of this project — the arrangement in LilyPond and the MIDI swing hack (written in Scheme). In doing so, I hope everyone finds a useful stocking stuffer. Ho ho ho!


Created by two Dutch musicians in 1996, GNU LilyPond is one of my favorite FOSS projects. It is currently maintained by a passionate and vibrant community of musicians and music enthusiasts.

LilyPond has a similar markdown language to LaTeX. In Let It Snow!, for example, the following input syntax:

gis8 e \times 2/3 { gis b cis } b cis4 b8

generates the following result in measure 52, voice two of the PDF:

An example of LilyPond notation

The other elements of the syntax are all explained in LilyPond's amazing documentation, which exists mostly due to a heroic effort by Graham Percival. For example, Let It Snow! contains key signatures, tempo indications, final bar lines, slurs, and partial measures. I have yet to run into something that LilyPond cannot do with some finagling.

The top-level organization of my LilyPond files tends to be like this:

\version "2.19.83" % version number, required
voiceOne = \relative c' {
  % some music
myScore = \new ChoralStaff << % or PianoStaff, or whatever
  \new Staff \new Voice \voiceOne
\header { %{ title, composer, etc %} }
\score { \layout { \myScore %{ some options for typesetting %} } }
\score { \midi { \myScore %{ some options for the midi %} } }
% various hacks

Start with a version number, then the music and optionally lyrics, then smoosh everything together into a score, then provide options for typesetting and for the MIDI if needed. Even though LilyPond's documentation is second to none, top-level organization of LilyPond files is a pain for newbies, and I find that pilfering other people's stuff is the best way to avoid tedious gotchyas and get that "wow" effect of a score on first compile. To see a few more use cases in vocal music, you can check out the repo for Sit Ozfårs Wysr. If you're a pianist, Google Keith O'Hara. If you're doing orchestral music, check out Werner Lemberg. Contemporary music? Trevor Bača. Check out these people's open-source scores, use them to make your own, and write great things!

It Don't Mean a Thing If It Ain't Got That…


LilyPond, without any coaxing, will generate a MIDI in straight-eighths and no swing, which is great for Bach, Buxtehude, Berstein, Beethoven, Brahms, Bruckner, and Bellini but not so great for Basie, Baker and Brubeck. There are many tricks one can use to make Lily swing, but they tend to be all-or-nothing, meaning that they will act on the global tempo map, which means that unswung parts will be ignored. This is particularly annoying when working with jazz arrangements that contain tuplets, which should never be swung.

To get around this, I wrote an ugly hack. But unlike many of my other hacks, this one works. My initial goal was to write it in a functional style, but for some reason that didn't pan out, so I used global variables to store tempo information. If anyone can see why the fold command isn't folding durations properly, please let me know. With that caveat, let's see how the sausage is made!

First, for anyone doing wholesale music manipulation in LilyPond, start by repurposing the naturalizeMusic example on this page. I've copied it below as well. It is stable, well written, and provides a useful template for most tweaking you'll need to do on a score.

#(define (naturalize-pitch p)
   (let ((o (ly:pitch-octave p))
         (a (* 4 (ly:pitch-alteration p)))
         ;; alteration, a, in quarter tone steps,
         ;; for historical reasons
         (n (ly:pitch-notename p)))
      ((and (> a 1) (or (eq? n 6) (eq? n 2)))
       (set! a (- a 2))
       (set! n (+ n 1)))
      ((and (< a -1) (or (eq? n 0) (eq? n 3)))
       (set! a (+ a 2))
       (set! n (- n 1))))
      ((> a 2) (set! a (- a 4)) (set! n (+ n 1)))
      ((< a -2) (set! a (+ a 4)) (set! n (- n 1))))
     (if (< n 0) (begin (set! o (- o 1)) (set! n (+ n 7))))
     (if (> n 6) (begin (set! o (+ o 1)) (set! n (- n 7))))
     (ly:make-pitch o n (/ a 4))))

#(define (naturalize music)
   (let ((es (ly:music-property music 'elements))
         (e (ly:music-property music 'element))
         (p (ly:music-property music 'pitch)))
     (if (pair? es)
          music 'elements
          (map (lambda (x) (naturalize x)) es)))
     (if (ly:music? e)
          music 'element
          (naturalize e)))
     (if (ly:pitch? p)
           (set! p (naturalize-pitch p))
           (ly:music-set-property! music 'pitch p)))

naturalizeMusic =
#(define-music-function (parser location m)
   (naturalize m))

In LilyPond, a score is represented as a Lisp list containing an arboreal structure of musical information. In the example above, naturalizeMusic is the top-level entry point that behaves like a LaTeX macro. Then, the function naturalize is a recursive function that acts on lists of elements, individual notes, and individual pitches of notes, drilling down through the tree until it gets to pitches. In the case of Let It Snow!, I do the same thing with rhythms. You can use the same strategy it with articulations, dynamics, or slurs, and the general pattern will always be the same. Lastly, naturalize-pitch actually does the heavy lifting on the pitches. In my version, the swing-duration function acts on a single duration, making it swing if it is contains an eighth note and otherwise leaving it untouched. The result is unswung tuplets and swung eighth notes coexisting in the same MIDI. w00t!

Parting Shot

Enjoy Let It Snow! The supporting materials talked about in this article are for anyone wishing to do their own arranging, coding, singing, or mixing. A big thank you to Timo Mäkelä for the editing and mixing, Jiffel for the facility, Bill Hare for mixing and mastering, Juuso Westerlund, and shout outs to Gustav Schulman, Maria Schulman and Matti Kari for helping find great locations for filming. I wish you all Happy Holidays and a Happy Roaring 20s!

Discussion (4)

Editor guide
deanius profile image
Dean Radcliffe

Really nice arrangement and video! I too had written a swing function for Lilypond and I believe it’s grown to be quite nice! Here’s a starting thread, I wonder why it didn’t show up in your searches

mikesol profile image
Mike Solomon Author

Wow, this is great stuff! For some reason this thread doesn't show up yet in the most popular search results, but hopefully the SEO algorithms will catch on.

I'd love to collaborate to incorporate some of the ideas from my script into your swing functions. What I like about your solution is that it provides a fine-grained approach to making specific sections swing. I wonder if there's a way to combine this with my approach, which applies swing to an entire piece based on certain assumptions?

peacefullatom profile image
Yuriy Markov

Thank you very much! This is amazing! 💖👍😊

mikesol profile image
Mike Solomon Author

Thanks Yuriy! Happy holidays :-)