Auto-update/make/compile script for Lilypond: Autolily

UPDATE July 24, 2010: This post is now totally obsolete. See this post instead.

I’ve so far used Lilypond twice to make nice, clean music of some classical pieces. If you don’t know what Lilypond is already, it is basically LaTeX, but for music. Since the music notation style is almost always the same across many different genres, LaTeX’s “what you see is what you mean” philosophy applies particularly well to your sheetmusic-making needs.

The basic way you work is — create an .ly file pursuant to the lilypond format, then save it, then call “lilypond [filename]” on it from the terminal, which will generate a .pdf, .ps, and .midi output all for you (that is, if you have a “\layout {}” and also a “\midi {}” in you “\score {}”). If you have dual monitors, then you can open up the .pdf file with evince, and then evince will automatically update to the latest .pdf version by itself (no need to close and re-open the same generated .pdf file).

This workflow is nice, but it could be better. For one, it takes time to switch windows and invoke “lilypond [filename]” every time you want to see a small change done. For me, I like to make sure at least every 1/2 measure or so that what I put in is correct. Thus, switching back and forth between all these windows every 30 seconds makes the whole process very time consuming.

So I wrote a small ruby script (I call it “Autolily”) to automatically invoke lilypond for me:

 1 #!/usr/bin/ruby
 2 #===============================================================================================================#
 3 # Program name: Autolily                                                                                        #
 4 # LICENSE: PUBLIC DOMAIN                                                                                        #
 5 # This program takes 1 argument, the name of a lilypond file (*.ly), and watches it for changes every 1 second. #
 6 # If there has been any change, it simply calls lilypond on it to create a new .pdf/.ps/.midi of it.            #
 7 #                                                                                                               #
 8 # Place this script somewhere, like in ~/scripts                                                                #
 9 # Then, open up a terminal and call it like so: ~/scripts/autolily.rb [lilypond file]                           #
10 # Be sure to call it from the directory where the lilypond file is located -- i.e., don't do [path/to/file]     #
11 #                                                                                                               #
12 # To exit, type CTRL-C.                                                                                         #
13 #===============================================================================================================#
15 if ARGV.size > 0
16     file = ARGV.shift
17     file_data_orig = ""
18     `ls --full-time`.split("\n").each do |line|
19         if line.split(/\s/).last == file
20             file_data_orig = line
21             break
22         end
23     end
24     file_data_new = ""
26     # enter infinite loop -- keep compiling the given lilypond file if it has changed in the past 1 second
27     while true
28         # detect the file size and also timestamp
29         lsarr = `ls --full-time`.split("\n")
30         lsarr.shift # get rid of the first line, since that is the size of all the files in the directory
32         # find our file from ls's output!
33         lsarr.each do |line|
34             if line.split(/\s/).last == file
35                 file_data_new = line
36                 break
37             end
38         end
40         # if there is any change detected, run lilypond on it
41         if file_data_orig != file_data_new
42             puts "\n\e[1;4;38;5;226mAutolily: Change detected in given file; invoking lilypond...\e[0m\n"
43             `lilypond "#{file}"`
44             file_data_orig = file_data_new
45         end
46         sleep 1
47     end
48 else
49     puts "No .ly file specified.\n"
50 end

This very simple script is an infinite loop which takes snapshots of the output of the “ls” command every second, and monitors any changes. Only the output line for the given lilypond file is monitored. Whenever this single line changes (any time you save your file, thus changing the modification timestamp of the file), the “lilypond [filename]” command is invoked to generate the .pdf, .ps, .midi outputs.

Now, every single time you save your .ly file, Autolily will run lilypond for you in the background, letting you know of any errors or such (and if you have evince open on the generated .pdf file, evince will update what your sheet music looks like as well).

Memory usage of this script is a bit embarrassing — I get around 4.5 MB — but hey, that’s Ruby’s fault.


UPDATE November 12, 2009: Added quotes around _file_ so that a filename with spaces works correctly. (Though, if you’re a Linux guy like me, you probably don’t name your files with spaces in them.)

One thought on “Auto-update/make/compile script for Lilypond: Autolily

  1. Hi, Shinobu. I just started working with LP, and immediately found myself wanting a solution like this. Thanks for sharing!


Comments are closed.