options(crayon.enabled = TRUE) sgr_wrap <- function(x, options){ paste0("<pre class=\"r-output\"><code>", fansi::sgr_to_html(x = htmltools::htmlEscape(x)), "</code></pre>") } knitr::knit_hooks$set(output = sgr_wrap) knitr::opts_chunk$set( collapse = TRUE, comment = "#>", message = FALSE, warning = FALSE, error = FALSE, tidy = FALSE, out.width = "100%" ) library(tabr)
This section covers lilypond()
and tab()
for writing LilyPond files and engraving to sheet music with LilyPond, respectively. Examples of the various pieces of metadata that can be passed to to these functions are provided.
The lilypond()
function creates a LilyPond file (.ly
). Various rendering functions wrap lilypond()
to combine the steps of creating an intermediary LilyPond file and rendering it to pdf or png. The most general render function is tab()
, which for naming consistency can also be called as render_tab()
. Other render_*
functions exist including render_score()
and render_midi()
, which focus on rendering non-tablature, all-purpose sheet music and rendering only the corresponding MIDI file, respectively.
The examples in this vignette focus on tab()
. You can set keep_ly = TRUE
in render functions to retain the intermediary LilyPond file.
By now you have seen many calls to tab()
throughout these vignettes in order to show full examples previously. With sufficient coverage of phrases, tracks and scores, and the progression through them, now it is time to go into more detail on the arguments that can be supplied as part of the rendering or engraving process that apply to the entire piece of sheet music.
These are the most critical components that can be supplied to lilypond()
. key
specifies the global key signature, e.g. key ="dm"
. Key signatures set for individual track override the global key, but the global key is used for any track whose key is NA
. Key changes in the middle of a song are not supported, but you can always edit the LilyPond file directly to make custom changes.
time
gives the time signature, defaulting to common time, "4/4"
. tempo
provides the song tempo, defaulting to tempo = "2 = 60"
, which is the LilyPond default. This can be read as 60 half note beats per minute.
Note that key
takes the tabr
key signature notation, but time
and tempo
which are used mostly in a transcription context like this, take values that match LilyPond format.
Throughout this tutorial section, the guitar and bass example from the section on tracks and scores is reused. The chord chart and chord sequence are retained to provide the most complete illustration of a rendered score. For completeness, here is what you have so far.
voice1 <- rp(p("c5 d5 e5 f5 g5", "1 2 4 4 1", "1*5"), 2) notes <- "c e g c' e' c' g e g b d' g' f a c' f' c e g e c" strings <- "5 4 3 2 1 2 3 4 4 3 2 1 4 3 2 1 5 4 3 4 5" voice2 <- rp(p(notes, "8*20 2", strings), 2) bass <- rp(p("c2e2*4 g1*2 f1*2 c2e2*3", "4*10 2", "32*4 4*4 32*3"), 2) t1 <- track(voice1, voice = 1) t2 <- track(voice2, voice = 2) t3 <- track(bass, clef = "bass_8", tuning = "bass") chords <- chord_set(c(c = "x32o1o", g = "355433", f = "133211")) chord_seq <- rep(setNames(c(1, 2, 2, 1), names(chords)[c(1:3, 1)]), 3) chords chord_seq song <- trackbind(t1, t2, t3, id = c(1, 1, 2)) |> score(chords, chord_seq) song
This time when rendering the song, use settings for the three arguments discussed above. Given what is written, it doesn't make sense to change them all. For example, this won't fit well as a waltz (time = "3/4"
). But for illustration purposes, pretend the song is actually in the key of D minor (F major). This key has one flat, Bb, so this will affect the display of the B note in the G chord. Change the time to 2/2
just for the sake of changing it, which won't really be any different from 4/4
except you will see a line through the common time symbol. Finally, change the tempo to 4 = 120
, which is also equivalent to the default, but will show up in the output slightly differently as well.
lilypond(song, "ex32.ly", "dm", "2/2", "4 = 120") tab(song, "ex32.pdf", "dm", "2/2", "4 = 120")
Notice how the key change alone, which added room for a single flat symbol to be squeezed into the start of the treble and bass clef staves, was enough to a line wrap compared to the previous tutorial section where it all fit on one line. This is because it was a tight fit to in the previous examples and there was not enough room for LilyPond to continue fitting everything on one line with this slight widening created by the key change. LilyPond generates sheet music with a somewhat responsive layout engraver. It won't necessarily leave everything on one line and push only a single measure to line two.
The output file specified with file
ends in pdf in every example. However, you can switch to png. Output is inferred from the file extension. file
can be a relative or absolute path to the file.
The next important argument to lilypond()
is header
. header
takes a named list of character strings that are used to fill in general song information such as the title and composer. All previous examples were blank above the tabs because none of this information was ever provided. Below an example is given that uses all available arguments. You can use any subset of these. There is no requirement to supply them all. This example just shows what is available. Several of these would likely not be used in most cases.
header <- list( title = "Song title", composer = "Words and music by the composer", performer = "Song performer", album = "Album title", subtitle = "Subtitle", arranger = "Arranged by tab arranger", copyright = "2018 <Record Label>", instrument = "guitar and bass", tagline = "A tagline", meter = "meter tag", opus = "opus tag", piece = "piece tag", poet = "poet tag" ) tab(song, "ex33.pdf", header = header)
The copyright and tagline are cutoff in the above image, but in your pdf you will see these if you scroll to the bottom of the rendered page.
You have probably noticed by now that every time a pdf if rendered, an accompanying MIDI file is also generated. This can be turned off with midi = FALSE
. This specification goes into the LilyPond file itself via lilypond()
. Therefore, no MIDI output will be created even if you create the LilyPond file with lilypond()
but convert that to pdf with LilyPond outside of R.
One thing to note about MIDI files is that tabr
will unfold any repeats that occur in a song due to calls to rp()
, pct()
or volta()
. This allows the MIDI file to play everything the proper number of times rather than ending prematurely by not being able to read repeat notation.
Also, tabr
is a package aimed at creating guitar tablature. It is not concerned with MIDI or audio signals and audio data in general. Any MIDI functionality is considered to be an extra feature and does not receive priority development or support. At this time, there is no way to make other alterations to the MIDI file internals. MIDI output can be toggled on or off as mentioned. And without you having to do anything, MIDI output will respect repeat notation in the rendered LilyPond file. MIDI output will also automatically be transposed to match a transposition that is applied to a music staff (under reasonable and simplified conditions).
The string_names
is only relevant for tablature staves. argument defaults to NULL
. This means that standard tuning is never specified alongside the lines of a tab staff at the beginning of the tablature. However, any other tuning will be explicitly noted so the reader is aware of the alternate tuning of any applicable track. This can also be set to TRUE
to force all tunings to be explicit including standard guitar tuning or FALSE
to suppress them all (though it is unclear what value there is in the FALSE
setting).
There is some nominal level of control over the paper layout via paper
. Like header
, this is a named list. The defaults are fine so you probably do not need to alter most of these values. There are six options, all numeric except for page_numbers
, which is logical.
textheight
linewidth
indent
first_page_number
page_numbers
fontsize
If you pass any values for some of these in a named list to paper
, any not passed will retain their built in defaults. You do not have to supply them all when using paper
.
There are also global color settings. You can pass a named list to colors
with any of the following. Values are hex colors or R color names.
color
background
staff_lines
time
clef
beam
head
stem
accidental
For more detail on these settings and others further above, see the help documentation for lilypond()
.
Here are examples that make use of png-specific options and function behavior. First, when rendering to png instead of pdf, automatic cropping of the image is attempted. This removes the full page appearance for smaller snippets of sheet music. There are some limitations to this. For example, inclusion of header elements can disrupt this behavior.
x <- pitch_seq("e,", 24, key ="c") |> as_music(8) |> p() |> track() |> score() ppr <- list(linewidth = 60, page_numbers = FALSE) hdr <- list(title = "Notes in C on guitar", subtitle = "Standard tuning") tab(x, "ex_png1.png", tempo = NULL, midi = FALSE, header = hdr, paper = ppr)
Above, the height is automatically cropped because file
type is a png. Providing textheight
to paper
overrides this behavior. The width would have also been cropped on its own. However, because of the inclusion of header
arguments, this fails and explicit linewidth
is needed. Similarly, if elements that describe footer content (still part of the LilyPond header
block) that appear at the bottom of the page such as tagline
or copyright
were included, automatic height cropping would have also failed. In general, automatic cropping is the default for png output, but header
disrupts this, requiring manual overrides to width and height.
In the example below, remove the header content. You can make a transparent background png, though you won't be able to see the difference here. Instead, create a dark mode example and increase the resolution.
Since this is a single voice, single track, you do not need to explicitly call each function in the transcription pipeline. Use one of the convenient render_music*
functions to abstract this process, rendering sheet music directly from a music
object. render_music_guitar()
has good default arguments for this example.
colors <- list(color = "#e4e4e4", background = "gray10", head = "tomato", tabhead = "tomato") x <- as_music(pitch_seq("e,", 24, key ="c"), 8) |> render_music_guitar("ex_png2.png", colors = colors, res = 300)
Finally, familiarize yourself with the LilyPond file itself. You may output a file and want to make additional edits to it directly. The example below also demonstrates some differences between simplify = TRUE
and simplify = FALSE
. This is a simple piece of music so not all possible syntax simplifications are shown here.
phrase()
objects have more robust structure that has advantages for performing object manipulations in R, but this is a more verbose version of LilyPond syntax. By default, lilypond()
as well as associated render_*
functions will simplify this to a more efficient syntax so that it is less cumbersome to read and work with LilyPond files directly.
There are other simplifications but the most notable benefits are the removal of all the <>
around single notes and not repeating consecutive durations if they are unchanged from previous timesteps.
lilypond(song, "song.ly", simplify = FALSE) cat(readLines("song.ly"), sep = "\n")
Here you can see the changes to the notation. Since the music is so short in this example, most of the file remains the same.
lilypond(song, "song.ly") cat(readLines("song.ly"), sep = "\n")
unlink(c("*.ly", "*.mid"))
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.