- Create a *.qmd file in one of the available subfolders.
- Add a yaml header to the file.
- Mandatory field(s):
title
- Optional field(s):
capo
,year
,artist
,time
,source
andtempo
(bpm) (see chordpro)
- Wrap chorus between
:::{.chorus} California dreamin (California dreamin') ... :::
- Add the path to the *.qmd file to
_quarto.yml
- Play the song
(For future me, what are the components that make this book work?)
I've had many iterations of this book. Initially in 2011, I stared out using Latex with the songbook package. I switched to Lynx at some point and just copy and pasted songs and displayed them in verbatim / monospaced fonts. This was all pdf based, so after a couple of years I switched to bookdown which could create both html and pdf outputs. I even created an R Package based on bookdown (songbookdown
), but found it too much work to maintain. I then quickly switched to the newly released software quarto and am very happy with the current status. I try to keep work on my side minimal and leverage pandoc extensions and lua filters to do the heavy lifting. I also try to keep the source files as simple as possible, so I can continue to copy and paste songs from popular websites without having to manually adjust them to my schema.
I use the following tricks to generate the book:
Since chords and text appear on separate lines, the font needs to be monospaced so that they are aligned correctly. See _quarto.yml
- pdf:
mainfont: FreeMono
- html:
font-family: 'Roboto Mono', monospace;
Since chords and text area only separated by single linebreaks, i needed to activate the extension hard_line_breaks
(see _quarto.yml
from
)
Since tabs sometimes rely on multiple dashes (-), and the extension smart
interprets two dashes (--) as an emdash, I needed to deactivate this extension (see _quarto.yml
from
)
Since chords have multiple spaces to align them to the right place in the text, i need spaces to be respected. To enable this, I created a preprocessor to replace all double spaces with no break spaces (see preprocessor.sh
)
For pdf, I want to make sure that even-paged-songs start on the left page, and odd-paged-songs appear on any page.
- I therefore switched to document class
memoir
, which has the optionsopenright
ANDopenleft
(other latex classes seem only to haveopenright
andopenany
). - I additionally implemented an SO solution where the number of pages per chapter is counted, and if this number is odd, the chapter is started on an odd page and vise versa.
For pdf output, I added \widowpenalties
1 10000 and \raggedbottom
to the preamble to prevent page breaks within paragraphs, i.e. verses.
I want to easily highlight the chorus using markdown.
- To do so, I installed the extension
latex-environment
with
quarto install extension quarto-ext/latex-environment`
- I then added the following to _quarto.yml
filters:
- latex-environment
environments: [chorus]
- Now, using the following syntax, I can easily add specify a chorus using the following syntax:
:::{.chorus}
California dreamin (California dreamin')
:::
- This will create a latex environment named chorus (it will also create a div (?) with the class "chorus"):
\begin{chorus}
California dreamin (California dreamin')
\end{chorus}
- This is not a valid latex environment yet. To make it so, I use the package
tcolorbox
. With the following three lines, I add create an environment named chorus
\usepackage{tcolorbox}
\tcbuselibrary{skins} % optional I think
\newtcolorbox{chorus}[1][Chorus]{left*=0mm,grow to left by=2mm,fonttitle=\small,title=#1}
% [1] means 1 optional argument (the title, where the default is "Chorus")
- With a clever interplay of the lua filter, html/css and latex/tcolorbox, I can do the following: Pass an alternative header as an option, e.g.
:::{.chorus options="Refrain"}
- In latex, the
tcolorbox
based environmentchorus
will interpret this as a custom title (since this is how I had prepared the environment in step before) - In html, this option will be stored as an attribute to the div (
data-options="Refrain"
). The appropriate html selectors will use this attribute ascontent
. If no such attribute is present, it will default toChorus
as content.
- In latex, the
I was adamant to add the song's metadata to the YAML header. I was sure there is a simple way to then extract this metadata and inject it into the documents body. I was right and I was wrong: There is a way, but its not that simple. But it is a chance to learn lua filters, which I've wanted to for a long time.
So with a little digging into lua filters and a lot of help from cscheid (on GitHub) I was able to come up with a lua filter that does exactly what I need (see add_to_title.lua
).
I don't want this book to become more complex that it already is. However, it's hard not to leverage even more of the power behind pandoc. For example, somebody built a lua filter that I could simply integrate into this book to generate chord diagrams for selected songs. More on this below.
Lilypond is a huge software for music notation. It does far more that I will ever need, but some subsets of the program might be interesting. What makes lilypond great is the fact that it is a text based command line program for which someone built a lua filter that can be included in pandoc. For example, assume the following lines are stored in a file named fretboard.md
(taken from here):
---
lilypond:
relativize: yes
---
```{.lilypond .ly-fragment ly-caption="A nice caption" ly-name="fretboard"}
\new FretBoards {
<f, c f a c' f'>1
}
With the command pandoc --lua-filter=lilypond.lua --extract-media=. --output=fretboard.html fretboard.md
, this file can be translated to html. For the sake of brevity, I will show here the output when converting it to a different markdown. Converting the file above with the following command pandoc --lua-filter=lilypond.lua --output=fretboard2.md fretboard.md
will produce the following output:
![A nice
caption](./fretboard.png "\new FretBoards { <f, c f a c' f'>1 }"){.lilypond-image-standalone}
where as fretboard.png is the following image:
(the fretboard is very pixellated since its only a tiny portion of a large image, I would need to debug this first). h