Announcing LilyBin + Clairnote

2017-06-16 — By Paul Morris — Clairnote Website, LilyPond

LilyBin is a website that offers a convenient web-based interface for using LilyPond.  While it is not fully-featured like Frescobaldi, it lets you try LilyPond without having to install it first and it lets you use LilyPond on a tablet or phone where (unfortunately) LilyPond can’t be installed.  Today I’m pleased to announce LilyBin + Clairnote, a version of LilyBin that supports Clairnote music notation. Check it out! And read on to learn about the technical details involved in making it.

LilyBin is implemented in two separate parts.  The inner part is basically “LilyPond as a service” — a server takes LilyPond text input, runs LilyPond on it, and gives back the output, say a PDF file (and/or a MIDI file).

The outer part is a node.js website/app that runs on a different server and handles everything else — all the aspects of the LilyBin user interface, communications with the “LilyPond as a service” server, saving LilyPond input files, etc.  (LilyBin can save files itself or via DropBox.)

While looking into the LilyBin code on GitHub I read that the LilyBin developers were fine with others using their “LilyPond as a service” directly.  That meant creating a modified version of LilyBin would not have to involve getting LilyPond up and running on a server, which always seemed like it would be difficult, given all of LilyPond’s dependencies, etc.

Also, I realized that it was already possible to get Clairnote output with LilyBin by simply cutting and pasting the contents of the file into the top of your LilyPond input. (This file, formerly named, contains the Scheme code that allows LilyPond to produce sheet music in Clairnote music notation, see Software: LilyPond.)  Cutting and pasting this code into an input file is functionally equivalent to “including” the file with the line \include "", which is the usual way to do it.

So all that was needed was a version of LilyBin that would pre-process the user’s input and if it found \include "" it would replace that text with the actual code from the file.  In other words, it would do the include operation itself before the input was processed by LilyPond.

After understanding LilyBin’s code, it was relatively straightforward to use regular expressions to find instances of \include "" in the input and do the substitution.  Making the Scheme code from available as a JavaScript string was a little trickier.  I used Frescobaldi to strip out all comments, and then I used regular expressions to find/replace excess whitespace and to escape certain characters.  I replaced all " with \" to escape double-quote characters, and replaced \ with \\ so forward-slash characters would be escaped and not escap_ing_.  In this way a 2000+ line file became one long minified JavaScript string on a single line. (!)

(Scheme uses backticks (`) so I wasn’t able to use JavaScript’s newer template literals because they also use backticks.  That’s too bad because they make it possible to quote raw (non-escaped) multi-line strings.)

To make it possible to comment out the \include "" line (just like you can when you are using LilyPond directly), I added another pre-processing step.  It simply removes all LilyPond comments from the input — both single-line and multi-line comments.

Next I made a few changes to the user interface, including disabling the native file saving feature. It’s in flux upstream, so I’ll wait for its implementation to settle down before re-enabling it. For simplicity’s sake I also disabled the save to DropBox feature for now. You can always simply cut and paste your LilyPond input to a text file. Finally, because my shared server plan does not support node.js, I deployed LilyBin + Clairnote on Heroku using a subdomain.

That’s it.  It works and it turned out to be simpler than I thought.  Sometimes inserting the right string at the right place is all it takes.  You can check out the source code here.

On second thought, a simpler and more elegant approach would be to add the file to the default directory of includable files that are part of LilyPond on the “LilyPond as a service” server.  (The “ly” directory as mentioned here.)  This would require setting up an instance of that server and adding the file whenever updating it or LilyPond to a new version. Then there would be no need to include the code “artificially” and the LilyPond input sent across the web would be much smaller, which might speed things up a bit.

Many thanks to Trevor Dixon, Timothy Gu, and the rest of the LilyBin developers for creating LilyBin and for licensing the code under an open-source MIT license, which made it possible to create this modified version that supports Clairnote music notation.  I am standing on your shoulders, as they say.

On a final note, this was a project I worked on while attending the Recurse Center, a wonderful “self-directed, community-driven educational retreat for programmers.”  It was an exercise in getting my feet wet with full-stack web development as most of my experience has been on the front-end.  Iain McCoy, a fellow recurser, gave me some valuable help with troubleshooting a few issues.  Thank you Iain and to everyone at the Recurse Center for a fantastic experience.

Give LilyBin + Clairnote a try!