Rendering sheet music is based on building up pieces of musical information culminating in a score. The fundamental object to consider in the transcription context is a phrase. A phrase is created from a noteworthy string and incorporates additional information, most importantly time and rhythm. It can also include positional information such as the instrument string on which a note is played. Outside of rendering tabs, there is no reason to construct phrase objects. Everything from the phrase object on up is about using the R to LilyPond pipeline to render some kind of sheet music document.
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.
phraseor the shorthand alias
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 unambiguous. For example, a rest followed by a sequence of notes might be given by
notes = "r a, c f d a f".
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 covered in the vignette tutorials.
The third argument,
string only applies to fretted string instruments and is always optional. In this example it specifies the strings of a guitar. Providing this information in conjunction with the pitch fixes the frets so that LilyPond does not have to guess them. This only applies for tablature output. Note that the
x shown below is just a placeholder indicating no need to specify a string for the quarter note rest. You can put a string number there but it is ignored.
Explicit string numbers are not needed for this example since is uses lowest fret numbers (the default). They are provided for a more complete example.
This is the general approach, but there are multiple ways to create equivalent phrase objects in
p1 <- phrase(notes = "r a, c f d a f", info = "4 8*6", string = "x 5 5 4 4 3 4") p1
#> <Musical phrase> #> r4 <a,\5>8 <c\5>8 <f\4>8 <d\4>8 <a\3>8 <f\4>8
As an aside, if you are working with the
music class, you can enter notes, note info, and optionally string numbers if applicable, all in a single string. This is not only potentially much more efficient for data entry, but can also be easier to follow because it binds these otherwise separate arguments by timestep. See the vignettes and help documentation relating to music objects for more details on working with these objects.
The phrase above can be constructed using the single-string input syntax that is used for music objects.
phrase understands this syntax and interprets the
notes argument as music syntax if the
info argument is not provided (
info = NULL). The phrase above could have been created as follows, with or without the optional explicit string numbering.
p("r4 a,8 c f d a f")
#> <Musical phrase> #> r4 <a,>8 <c>8 <f>8 <d>8 <a>8 <f>8
p("r4;5 a,8 c f;4 d a;3 f;4")
#> <Musical phrase> #> r4 <a,\5>8 <c\5>8 <f\4>8 <d\4>8 <a\3>8 <f\4>8
Notice how each timestep is complete within the single character string inputs above. Also, durations and string numbers can repeat implicitly until and explicit change occurs. String numbers are ignored when they carry over rests. This is often a more convenient way to construct phrases. If you already have a music object, it can be passed directly to
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 concatenated together. Tracks are just tibble data frames with an additional track class.
track1 <- track(p1) track1
#> # A tibble: 1 x 7 #> phrase clef key tab tuning voice lyrics #> <list> <chr> <chr> <lgl> <chr> <int> <chr> #> 1 <phrase> treble_8 NA TRUE e,a,dgbe' 1 NA
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 8 #> phrase clef key tab tuning voice lyrics id #> <list> <chr> <chr> <lgl> <chr> <int> <chr> <int> #> 1 <phrase> treble_8 NA TRUE e,a,dgbe' 1 NA 1
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.
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.
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.
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.