
Last chance! 50% off unlimited learning
Sale ends in
Author: Matthew Leonawicz License: MIT
The tabr
package provides a music notation syntax and a collection of
music programming functions for generating, manipulating, organizing and
analyzing musical information in R. The music notation framework
facilitates creating and analyzing music data in notation form.
Music programming in the notation syntax provided by tabr
can be used
for a variety of purposes, but it also integrates cohesively with the
package’s transcription functions. The package also provides API wrapper
functions for transcribing music notation in R into guitar tablature
(“tabs”) using LilyPond.
LilyPond is an open source music engraving program for generating high
quality sheet music based on markup syntax. tabr
generates LilyPond
files from R code and can pass them to LilyPond to be rendered into
sheet music pdf files from R. While LilyPond caters to sheet music in
general and tabr
can be used to create basic sheet music, the
transcription functions focus on leveraging LilyPond specifically for
creating quality guitar tablature.
While LilyPond is listed as a system requirement for tabr
, you can use
many package functions without installing LilyPond if you do not intend
to render tabs.
tabr
offers a useful but limited LilyPond API and is not intended to
access all LilyPond functionality from R, nor is transcription via the
API the entire scope of tabr
. If you are only creating sheet music on
a case by case basis, write your own LilyPond files manually. There is
no need to use tabr
or limit yourself to its existing LilyPond API or
it’s guitar tablature focus.
However, if you are generating music notation programmatically, tabr
provides the ability to do so in R and offers the added benefit of
converting what you write in R code to the LilyPond file format to be
rendered as printable sheet music.
With ongoing development, the music programming side of tabr
will
likely continue to grow much more than the transcription functionality.
LilyPond is an exceptional sheet music engraving program.
tabr
is the bottleneck in
transcription limitations rather than the music engraving software
it wraps around.The tabr
package offers the following:
You can install tabr from CRAN with:
install.packages("tabr")
You can install tabr from GitHub with:
# install.packages("remotes")
remotes::install_github("leonawicz/tabr")
As a quick introduction and to get oriented to the music notation syntax
offered by tabr
, consider the concept of a noteworthy string. This is
like any other character string, except that what makes a string
noteworthy is that its content consists strictly of valid tabr
music
notation syntax. It can be parsed unambiguously and meaningfully into a
musical phrase (see next section) and can be processed as input to the
various package functions that inspect and manipulate musical
information.
A simple character string like "c e g"
, or alternatively as a vector,
c("c", "e", "g")
, is a noteworthy string. Even "a"
is noteworthy. So
are "a#"
and "a_"
(sharp and flat). However, "A"
is not, nor is
"Z"
. There are other pieces of valid syntax than just the lowercase
letters a
through g
and sharp and flat notation. See the package
vignettes for details.
Noteworthiness can be checked on any character string. No supplemental
class is required. When defining noteworthy strings you can define them
like any other character vector. However, you will notice that package
functions that operate on noteworthy strings and whose output is another
noteworthy string will yield a string with the supplemental noteworthy
class. This has its own print and summary methods. If you remove the
class with a common R operation like as.character()
, it does not
impact any subsequent musical manipulation beyond the need to reperform
a noteworthy check.
x <- "g#4 c5 d#5 g#4c5d#5"
as_noteworthy(x)
#> <Noteworthy string>
#> Format: space-delimited time
#> Values: g#4 c5 d#5 <g#4c5d#5>
is_note(x)
#> [1] TRUE TRUE TRUE FALSE
is_chord(x)
#> [1] FALSE FALSE FALSE TRUE
chord_is_major(x)
#> [1] NA NA NA TRUE
(x <- transpose(x, 1))
#> <Noteworthy string>
#> Format: space-delimited time
#> Values: a4 c#5 e5 <a4c#5e5>
summary(x)
#> <Noteworthy string>
#> Timesteps: 4 (3 notes, 1 chord)
#> Octaves: integer
#> Accidentals: sharp
#> Format: space-delimited time
#> Values: a4 c#5 e5 <a4c#5e5>
distinct_pitches(x)
#> <Noteworthy string>
#> Format: space-delimited time
#> Values: a4 c#5 e5
distinct_pitches(x) %>% pitch_freq() # in Hz
#> [1] 440.0000 554.3653 659.2551
tabr
offers many functions for manipulating musical structures defined
in music notation. See the vignettes for more information on music
programming.
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.
If you doing music analysis on noteworthy strings and are combining the note, pitch or chord information with time, that can be done with a corresponding variable; using a phrase object is not the way to do that because phrase objects are intended for the construction of LilyPond markup syntax.
As a brief example, recreate the tablature shown in the image above (minus the R logo). Here are the steps.
phrase
or the shorthand alias p
.track
.score
.tab
.The code is shown below, but first some context.
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 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.
The example below employs a couple shortcuts to further reduce typing.
The first is to use the *
in-string expansion operator mentioned above
to avoid typing a long series of eighth notes. Second, it drops explicit
reference to octave number three since this central octave is the
default octave in LilyPond. This applies to all but the first note
below.
While explicit string numbers are not needed for this example, they are
provided anyway for full context. Dropping the string
argument would
further reduce typing.
Finally, specify some song metadata to reproduce the original staff: the key of D minor, common time, and the tempo.
If LilyPond is installed on your system (and added to your system path
variable on Windows systems), tab
should call it successfully. Windows
users are recommended to just add LilyPond’s bin
directory to the
system path. This will take care of LilyPond as well as its bundled
Python and MIDI support. As an example for Windows users, if the
LilyPond executable is at C:/Program Files
(x86)/LilyPond/usr/bin/lilypond.exe
, then add C:/Program Files
(x86)/LilyPond/usr/bin
to the system path.
library(tabr)
p("r a2 c f d a f", "4 8*6", "x 5 5 4 4 3 4") %>% track %>% score %>%
tab("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
For comparison, if you were using string-fret specification to construct the above phrase, one way to do so is the following:
sfp("r;r;4 5;0;8 3 4;3; 0 3;2; 4;3;")
#> <Musical phrase>
#> r4 <a,\5>8 <c\5>8 <f\4>8 <d\4>8 <a\3>8 <f\4>8
It may not look particularly beneficial here, but for more complex music
it can be easier to reason about the phrase under construction when
using this format to bind information by time step rather. See
?sf_phrase
for a comparison with phrase
and the various ways you can
do phrase construction in tabr
for equivalent results. If you are
looking to do quick, easy and basic tabbing, you may want to consider
using the single-argument input method of the sf_phrase
function. The
package vignettes focus on general use cases using the phrase
function
rather than sf_phrase
.
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. 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.
There are several vignette tutorials and examples at the tabr
website.
R-Music
R for music data extraction and analysis
See the R-Music organization on GitHub for more R packages related to music data extraction and analysis. The R-Music blog provides package introductions and examples.
Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.
install.packages('tabr')