crumbly::liquid

I created song book (well two actually)

2026-01-27

So I wanted to create a song book. Why? Well a group that I'm a part of already had a song book, great! But I wanted to create my own "fork" if you will. With songs that were in previous iterations of this song book but I also wanted to add my own favourite songs.

My issue with it was that it was made in Microsoft Word a there were multiple issues with it. If I put aside the inconsistent typesetting, my main issue was that the chord alignment was bad and adding songs to it would be very labor intensive.

So what I really wanted, was a songbook that would accomplish the following:

Now at that point I hadn't even though about my requirements. I just wanted my own song book that was better that the one before.

OpTeX

And so it happened that right around that time I came across OpTeX. From the OpTeX website OpTeX is a LuaTeX format (LuaHBTeX format since 2025) based on Plain TeX macros (by Donald Knuth).

It's basically a bunch of macros built on top of TeX the same way that LaTeX is (as far as my understanding goes) but it aims to be much simpler and tries to not obfuscate the ways TeX works from the user.

I'm not going to go into the details of OpTeX or it's advantages or disadvantages over LaTeX as I don't have enough knowledge and experience with either. What's important is that I though that it was cool and wanted to play with it.

At the start I was pretty much lost. Knowing little TeX apart from some basics from my limited LaTeX usage, I was pretty much lost. But to my rescue came csongbook! Marcos for typesetting songs with chords and an example of the whole song book! Now this didn't do exactly what I wanted but it gave me reference which I could work from.

I created my own set of macros (that were sometimes just more readable rewrites of the ones provided) and with them I created my first song book!

It was... fine. I could typset chord nicely and adding new songs wasn't too bad. One cool feature I managed to add thanks to OpTeX being base on LuaTeX was customizable transposition but the developer experience was horrible especially when I had to handle hashes (#) for chords was very frustrating.

And to be honest it took me quite a while to port all of the song from the old song book over to the new one. And while it probably wasn't as frustrating as doing it in Microsoft Word, it wasn't exactly painless either. Every chord had to be a macro call and the chords woudn't be even automatically spaced, you had to specify the spacing manually!

This was an improvement but not as good as I had hoped.

Returning to the requirements (which I hadn't formulated yet at that point):

Typst

After I had finished the first version in OpTeX I wanted to add the chord spacing but it turns out that I'm terrible at TeX and was pretty much lost as to where I could start. And same as before, at some point I discovered a new cool thing! This time it was Typst.

Typst is a powerful typesetting system with a pretty good language desing that greatly improves over the status quo (that being TeX/LaTeX). It isn't without it's issues but in a lot of areas it's already miles better than (La)TeX.

So of course I decided to rewrite my song book in Typst! Again without much of a plan :D. I found a couple packages that did something simmilar but not exactly what I wanted. So I took inspiration from the one that worked mostly like I wanted and made my own version. This was much easier that my frist try with OpTeX. Partly because I knew what I was going for but mainly because Typst provides a much better developer experience and is way more intuitive (once you get to know the building blocks properly).

And the result looks pretty good! Chord spacing works pretty well (with some minor caveats) and implementing chord transposition is very easy! Porting the songs over wasn't exactly easy but nothing that a bunch of sed scripts stitched together couldn't handle.

Okay! Problem solved then? Well... Not really.

I have a nice song book which looks good and works well but adding to it isn't exactly easy :(

Custom format

This is when I am now. Seeing as using existing typsetting systems directly won't give me the qulities I want I decided to create my own format!

I want a format that is simple to parse yet extensible for when I want some specific typesetting options or other possible metadata attached. But first let's see what other formats are out there!

Chord Charts File Formats

One would think that I would've done this research before embarking on this journey. Well better late then never, so I'm doing this now!

As far as I can tell there are basically two formats.

The first one is the simplest format one could think of. Just write the text and then place character (chords) directly above the lyrics separated by a bunch of spaces for the right alignment.

This sort of works as it's probably the easiest to understand from a user's perspective but it's also very annoying to create and maintain. If I want to change anything I'll have to align all of the chords again!

The other widely used format is the ChordPro format. ChordPro is actually a program that can generate chord-over-lyrics style output based on the input given in their format. And other program seemingly adopted its format too!

ChordPro File format

The ChordPro format is actually quite simple!

Anything inside square brackets ([]) is treated as a chord but it's also sometimes a shorthand for a section(?).

Anyything inside curly brackets ({}) is then treated as a directive with some key and optionally a value separated from its key with a colon (:).

There are a bunch of predefined directives such as {start,end}_of_{verse,chorus,bridge,...} or other directives like transpose, title, comment or image.

I like that lyrics and other metadata is separated however I don't really like the syntax of it. I also don't like the fact that you can't attach a chord to a specific string of text and you have to just sort of put it at the start which sometimes results in misleading chord placement.

I also don't like that one has to first start a verse and then end a verse. It would be great if this could be one block or perhaps could be defined implicitly based on the number of line endings the same way it's done in LaTeX or Markdown.

To be continued...

And this is where I'm now. I've tried to design a couple options and so far I don't like what I've got.

This is my current best version yet but I think this is going to need a lot more thought before I pull the trigger and start writing a parser for it.

@title Undisclosed Desires
@author Muse
@capo 3
@transpose -4
@meta.composer { David Baker }
@meta.description {
  This is a long multiline description
  of this song!
}

#[verse]
  [C]I know you've suffered
  But I [Emi]don't want you to hide
  [C]It's cold and loveless
  I won't [Emi]let you be denied
  [C]Soothing
  // Chords range can be specified
  // with angled brackets
  I'll [Emi]{make} you feel pure
  And [C]trust me
  [Emi]You can be sure

#[chorus.first] {
  [Ami]I want to [C]reconcile the [Emi]violence in your [G]heart
  [Ami]I want to [C]recognize your [Emi]beauty's not just a [G]mask
  [Ami]I want to [C]exorcise the [Emi]demons from your [G]past
  [Ami]I want to [C]satisfy the [Emi]undisclosed [G]desires in your [C]heart
}

The idea for this DSL is the following:

All content is delimited by curly braces which is consistent across all of the constructs and feels nice to me.

I think the way metadata is structured is fine and I like that it's visibly different from other elements but I'm not sure if metadata should be strictly strings for setting stuff like title, transposition or font size or if they should function more like directives in ChordPro and be able to for example set it's content to bold.

It's nice because it's all metadata but I don't like the fact that one doesn't know what a compiler will do with a specific meta tag. It would be good for formatting meta tags such as bold to still cause parsers that don't support it to emit the text inside it even if it doesn't support the specified tag.

The best option would be to separate metadata tags from formatting tags but I haven't landed on a nice syntax yet.

I definitely don't want to change the syntax for chords as I really like the syntax and it preserves at least some compatiblity with songs written for ChordPro which will make porting songs over somewhat easier.

Closing thoughts

And that's it. I'll probably sit and work on this once in a while and I'll update this article when get to another version that'll be hopefully nicer with better defined syntax and semantics!