Basic example

A good place to start is with a simple, reproducible example that outlines the basic flow from small, succinct musical phrases, which combine to form tracks, in turn combined into a score, and ending with engraving the score to familiar sheet music. The brief example below recreates the single measure of guitar tablature shown in the tabr logo. Here are the steps as a list.

Constructing a musical phrase

A phrase here does not require a strict definition. Think of it as the smallest piece of musical structure you intend to string together. The first argument to phrase is a string describing notes of a specific pitch (or rests: “r”), separated in time by spaces. For chords, just remove spaces to indicate simultaneous notes. Integers are appended to indicate the octave number so that the pitch is unique. For example, a rest followed by a sequence of notes might be given by notes = "r a2 c3 f3 d3 a3 f3".

The second argument is a similar string giving note metadata. In this example there is nothing to add but the time durations. Whole notes taking up an entire measure of music are given by 1, half notes by 2, quarter notes 4, eighth notes 8, and so on. To specify a quarter note rest followed by a sequence of eighth notes, use info = "4 8 8 8 8 8 8" (or shorten to just info = "4 8*6"). This basic example does not require specifying additional note information such as dotted notes for different fractions of time, staccato notes, ties/slurs, slides, bends, hammer ons and pull offs, etc. These specifications are currently available in tabr to varying degrees of development and are covered in the vignette tutorials.

The third argument, string, is optional but generally important for guitar tablature. In similar format, it specifies the strings of the guitar on which notes are played. Providing this information fixes the fret-string combinations so that LilyPond does not have to guess what position on the neck of the guitar to play a specific note. An inability to specify this in various tablature notation software (or laziness by the user), is a common cause of inaccurate tabs scouring the internet, where even when the notes are correct they are written in the tab suggesting they be played in positions no one would sensibly use. Note that the x shown below is just a placeholder indicating no need to specify a string for the quarter note rest.

library(tabr)
phrase(notes = "r a2 c3 f3 d3 a3 f3", info = "4 8 8 8 8 8 8", string = "x 5 5 4 4 3 4")
#> r4 <a,\5>8 <c\5>8 <f\4>8 <d\4>8 <a\3>8 <f\4>8

The print method for phrase uses cat rather than print. The phrase strings print more cleanly this way, given the preponderance of backslashes. This result shows (one way) how to write the LilyPond markup.

Before going further, a brief aside on how there is no free lunch, no way to be completely unambiguous with the music notation while greatly restricting the amount of typing. Ultimately, every song is unique and must be written out differently in R just as in LilyPond or elsewhere. While doing this programmatically can be highly efficient for writing out new sections or editing existing sections of music that are highly repetitive, there will always be just as many instances of musical sequences that are not sufficiently repetitive, incorporating subtle deviations, or highly unpatterned sections like a guitar solo.

There is no way around it; even in cases where using tabr as a wrapper is much more convenient than typing out a LilyPond file directly, there can still be plenty of typing. Generic coding to avoid code duplication is helpful, but is never going to be a magical solution enabling extreme code reduction when writing all but the simplest and most boring musical scores.

In the interest of minimizing typing, there are several shortcuts available in tabr. The example below reproduces the same phrase. The first shortcut is to use the * in-string expansion operator mentioned above to avoid typing a long series of eighth notes. Second, drop explicit reference to octave number three since this central octave is the default octave in LilyPond. This applies to all but the first note. Explicit string numbers are also not needed for this phrase. Another thing that you can do is use the alias p for phrase. It is also fine to drop the argument names, as they will be used often and remembering them will not be difficult. Use all these shortcuts and store the phrase:

p1 <- p("r a2 c f d a f", "4 8*6")

Tracks

Track construction is as simple as wrapping a phrase object in track. This example uses a single phrase. Typically a track would consist of many phrases glued together. Tracks are just tibble data frames with an additional track class.

track1 <- track(p1)
track1
#> # A tibble: 1 x 6
#>   phrase       tuning         voice staff    ms_transpose ms_key
#>   <list>       <chr>          <int> <chr>           <int> <chr> 
#> 1 <S3: phrase> e, a, d g b e'     1 treble_8            0 <NA>

Scores

The complete score is composed of one or more tracks. This example has only a single track. Just as the track constructor takes phrases, the score constructor takes tracks as inputs. Score objects are tibble data frames with an additional score class.

song <- score(track1)
song
#> # A tibble: 1 x 7
#>   phrase       tuning         voice staff    ms_transpose ms_key tabstaff
#>   <list>       <chr>          <int> <chr>           <int> <chr>     <int>
#> 1 <S3: phrase> e, a, d g b e'     1 treble_8            0 <NA>          1

Calling LilyPond from R

Once a score object is created, it is ready to be sent to LilyPond. If LilyPond is installed on your system (and added to your system PATH variable on Windows systems), tab should call it successfully. Alternatively, on Windows, it can be added explicitly by calling tabr_options. This option to specify the LilyPond path is still available on other systems. An example of this is commented out below. However, tabr will do its best on package load to set these paths in tabr_options for you if it can successfully detect a LilyPond installation in a standard file system location, so you may not have to do anything. Just check tabr_options() after you load the package. If any of the paths are equal to the empty string "", then you need to set the paths. Otherwise you should be ready to run LilyPond from R.

# may not be necessary
# tabr_options(lilypond = "C:/Program Files (x86)/LilyPond/usr/bin/lilypond.exe")

Technically, when loading tabr on Windows it will attempt to check the specific path above to see if lilypond.exe exists there. If it does, the path in tabr_options will be filled in for you. Therefore, if you need to specify the LilyPond path because it is not in your PATH environment variable and nothing shows in tabr_options(), then the path shown above is probably not where you installed LilyPond.

Score metadata

Other than ensuring LilyPond is accessible, there is only one function left to call in this series of steps to produce the sheet music. tab takes several arguments, many of which are optional and have default values. However, since music is so variable it makes sense to specify these arguments every time. These arguments include metadata about the piece such as key signature, time signature, tempo, title, author, and so on. Most of that is not needed here, but for good practice at least be unambiguous about the music itself and specify a key signature, time signature and tempo.

tab(song, "phrase.pdf", key = "dm", time = "4/4", tempo = "4 = 120")
#> #### Engraving score to phrase.pdf ####
#> GNU LilyPond 2.18.2
#> Processing `./phrase.ly'
#> Parsing...
#> Interpreting music...
#> Preprocessing graphical objects...
#> Interpreting music...
#> MIDI output to `./phrase.mid'...
#> Finding the ideal number of pages...
#> Fitting music on 1 page...
#> Drawing systems...
#> Layout output to `./phrase.ps'...
#> Converting to `./phrase.pdf'...
#> Success: compilation successfully completed

This log output will be printed at the R console. Load the new pdf file to see the result. It should look like this.

Piping

Note above that tabr also exports the pipe %>% operator. Even given the hierarchy of objects involved in the series of steps to move from a phrase to a rendered pdf, a short example like this does not even require a single assignment. The same steps involved in building up the structure and rendering the output could be performed as follows.

p("r a2 c f d a f", "4 8*6") %>% track %>% score %>%
  tab(song, "phrase.pdf", key = "dm", time = "4/4", tempo = "4 = 120")

While music can be quite complex and a full score will be much longer, tabr strives to minimize the work while still forcing some sense of interpretable, organized structure. For long and complex music, it can require some effort and practice to ensure your approach to transcription in your R code is not opaque.

To recap, the phrase is defined, added to a track, the track is added to a score, and the score is rendered to tablature in a pdf file with tab. The next tutorial section discusses phrases in more detail and provides an overview of the different notes and note metadata that can be specified when constructing a phrase.