knitr::opts_chunk$set( collapse = TRUE, comment = "#>", # To prevent CRAN from building this vignette: # # 1. Add `BUILD_VIGNETTE=TRUE` in .Renviron before calling # `devtools::build()` or `R CMD build`, to build this vignette locally. # # 2. Remove `BUILD_VIGNETTE=TRUE` before calling `R CMD check --as-cran`. eval = Sys.getenv("BUILD_VIGNETTE") == "TRUE" )
library(gm)
There are two interpretations of the package name gm:
They correspond to two functionalities of the package:
Let's start with a quick example.
music <- Music() + Meter(4, 4) + Line(c("C5", "D5", "E5", "F5")) show(music)
Let's go through the code line by line:
music <-
defines a variable.Music()
initializes a Music
object.+ Meter(4, 4)
adds a 4/4 time signature.+ Line(c("C5", "D5", "E5", "F5"))
adds four notes.show(music)
generates the music.We don’t have to stop here. We can add more components. For example, add a tempo:
music <- music + Tempo(180) show(music)
Add an articulation:
music <- music + Articulation(">", 1) show(music)
Add a pedal:
music <- music + Pedal(1, 4) show(music)
There are still many other components we can add. Before we dive in, let's see how to install and configure gm.
Install gm:
install.packages("gm")
Install MuseScore. MuseScore is open source and free notation software. Internally, gm uses MuseScore to generate music.
You don’t need to configure anything if MuseScore is installed to a default path.
Otherwise, please specify the path to the MuseScore executable file in .Renviron file:
MUSESCORE_PATH=<path to MuseScore>
.For example, the environment variable is like
MUSESCORE_PATH=C:/Program Files/MuseScore 4/bin/MuseScore4.exe
in Windows, andMUSESCORE_PATH=/Applications/MuseScore\ 4.app/Contents/MacOS/mscore
in macOS.At the highest level, gm uses Music
objects to represent music.
As shown in the Example section, the workflow for creating music is usually like this:
Music
object with Music()
.+
.show()
.A Music
object is represented as a list of data frames. Each data frame represents some type of components of the music. To examine a Music
object's representation, simply print it. For example, below is the representation of the Music
object created in the Example section:
music <- Music() + Meter(4, 4) + Line(c("C5", "D5", "E5", "F5")) music
We will explore every type of components as we proceed.
Musical lines are the most basic units of music in gm. You can create a musical line with Line()
.
You can specify the pitches and durations of a musical line with arguments pitches
and durations
. For example:
line <- Line( pitches = c("C5", "D5", "E5", "F5"), durations = c(0.5, 1, 1.5, 2) ) music <- Music() + Meter(5, 4) + line show(music, "score")
If pitches
and durations
have different lengths, the shorter one will be recycled. This feature is useful for repeating a pattern. For example:
line <- Line( pitches = c("A3", "E4", "C5", "B3", "E4", "G#4"), durations = c("quarter.", "eighth", "quarter") ) music <- Music() + Meter(3, 4) + line show(music)
We will talk more about pitches and durations later.
You can insert a musical line at positions other than the first beat of the first bar with arguments bar
and offset
. For example:
line <- Line(c("C5", "D5", "E5"), bar = 2, offset = 1) music <- Music() + Meter(4, 4) + line show(music, "score")
The musical line is inserted at the second beat of the second bar.
A more interesting example:
pitches <- c(64, 65, 69, 71, 72, 76) music <- Music() + Meter(4, 4) for (i in 0:8) { music <- music + Line(pitches, offset = 0.5 * i) } show(music)
The music contains nine parts, with identical pitches and durations. The difference lies in their insertion positions, creating an interesting echo sound effect.
Music can contain more than one musical line. For example:
line_1 <- Line(c("C5", "D5", "E5", "F5")) line_2 <- Line(c("E4", "G4"), 2) line_3 <- Line("C4", 4) music <- Music() + Meter(4, 4) + line_1 + line_2 + line_3 show(music, "score")
You can assign a name to a musical line with argument name
. For example:
line_1 <- Line(c("C5", "D5", "E5", "F5"), name = "a") line_2 <- Line(c("E4", "G4"), 2, name = "b") line_3 <- Line("C4", 4, name = "c") music <- Music() + Meter(4, 4) + line_1 + line_2 + line_3 show(music, "score")
By default, a musical line is added to the end. You can change it with argument to
and after
. For example:
line_1 <- Line(c("C5", "D5", "E5", "F5"), name = "a") line_2 <- Line(c("E4", "G4"), 2, name = "b") line_3 <- Line("C4", 4, name = "c", to = "a", after = FALSE) music <- Music() + Meter(4, 4) + line_1 + line_2 + line_3 show(music, "score")
Now the third musical line is added to the beginning.
There is a hierarchy of musical lines:
From the perspective of a music score,
You can specify the hierarchy with argument as
. For example, the following music has two parts:
music <- Music() + Meter(4, 4) + Line(c("C5", "D5", "E5", "F5")) + Line(c("C4", "G4"), 2, as = "part") show(music, "score")
The following music has one part, and this part has two staffs:
music <- Music() + Meter(4, 4) + Line(c("C5", "D5", "E5", "F5")) + Line(c("C4", "G4"), 2, as = "staff") show(music, "score")
The following music has one part of one staff, and this staff has two voices:
music <- Music() + Meter(4, 4) + Line(c("C5", "D5", "E5", "F5")) + Line(c("C4", "G4"), 2, as = "voice") show(music, "score")
Actually, the three examples above all sound the same. The hierarchy of musical lines is only discernible from the score.
The following music has one part of one staff of one voice, and this voice has two segments:
music <- Music() + Meter(4, 4) + Line(c("C5", "D5", "E5", "F5")) + Line(c("C4", "G4"), 2, as = "segment", bar = 2) show(music, "score")
Segments are used to insert musical lines into other musical lines.
The $lines
data frame of a Music
object contains the information about all musical lines. For example:
line_1 <- Line(c("C5", "D5", "E5", "F5"), name = "a") line_2 <- Line(c("E4", "G4"), 2, name = "b", as = "voice") line_3 <- Line("C4", 2, name = "c", as = "staff", offset = 2) music <- Music() + Meter(4, 4) + line_1 + line_2 + line_3 show(music, "score")
music$lines
We can see from the data frame that this music has one part, and this part has two staffs. The first staff has two voices. The second staff is inserted at the third beat.
You can use scientific pitch notations to specify pitches. For example:
pitches <- c("C4", "C#4", "D-4", "C##4", "D--4") music <- Music() + Meter(5, 4) + Line(pitches) show(music, "score")
A pitch notation consists of
A MIDI note number is a number between 12 and 127. You can also use MIDI note numbers to specify pitches. For example:
pitches <- 61:64 music <- Music() + Meter(4, 4) + Line(pitches) show(music, "score")
See a conversion table of pitch notations and MIDI note numbers.
An advantage of MIDI note numbers is ease of operation. Suppose we have the following four MIDI note numbers:
pitches <- c(60, 62, 64, 65) music <- Music() + Meter(4, 4) + Line(pitches) show(music)
To transpose them up by a fifth, we can simply add 7 to them:
pitches <- pitches + 7 music <- Music() + Meter(4, 4) + Line(pitches) show(music)
However, a disadvantage of MIDI note numbers is ambiguity. For example, there is more than one equivalent pitch notation to the MIDI note number 73:
pitches <- c("C#5", "D-5", "B##4") music <- Music() + Meter(3, 4) + Line(pitches) show(music, "score")
gm interprets MIDI note numbers based on keys and neighbor pitches. In the following example, MIDI note number 73 is interpreted as C#5 in the first measure, but as D-5 in the second measure:
pitches <- c(73, 73) music <- Music() + Meter(1, 4) + Key(7) + Key(-7, bar = 2) + Line(pitches) show(music, "score")
You can use NA
to specify rests. For example:
pitches <- c("C4", NA, "D4", NA) music <- Music() + Meter(4, 4) + Line(pitches) show(music, "score")
Sometimes rests are added by gm automatically. In the following example, the musical line is inserted at the second bar, so a rest is added to the first bar:
pitches <- c("C4", NA, "D4", NA) music <- Music() + Meter(4, 4) + Line(pitches, bar = 2) show(music, "score")
In the following example, the musical line doesn’t fill the entire bar, so some rests are added to the end:
pitches <- "C4" music <- Music() + Meter(4, 4) + Line(pitches) show(music, "score")
You can use vectors to specify chords. Just remember to wrap them in a list. For example:
pitches <- list("C4", c("E4", "G4"), NA, c(64, 67)) music <- Music() + Meter(4, 4) + Line(pitches) show(music)
You can use Key()
to add a key signature. All keys:
keys <- -7:7 for (key in keys) { print(Key(key)) }
You can add a key signature to a specific bar by using the bar
argument. For example:
music <- Music() + Meter(1, 4) + Line(durations = rep(1, length(keys))) for (i in seq_along(keys)) { music <- music + Key(keys[i], bar = i) } show(music, "score")
You can add a key signature only to a part or staff. For example:
music <- Music() + Meter(1, 4) + Line(NA) + Line(NA, as = "staff") + Line(NA) + Line(NA, as = "staff") + Key(1, to = 1) + Key(-1, to = 3, scope = "staff") show(music, "score")
Key(1, to = 1)
adds a G major to the first musical line and it affects the whole part, while Key(-1, to = 3, scope = "staff")
adds an F major to the third musical line and it affects only that corresponding staff.
You can use Clef()
to add a clef. For example:
clef <- Clef("F") music <- Music() + Meter(2, 4) + Line(c("C3", "D3")) + clef show(music, "score")
All supported clefs:
Clef("G") Clef("G", line = 1) Clef("G", octave = 1) Clef("G", octave = -1) Clef("F") Clef("F", line = 3) Clef("F", line = 5) Clef("F", octave = 1) Clef("F", octave = -1) Clef("C") Clef("C", line = 1) Clef("C", line = 2) Clef("C", line = 4) Clef("C", line = 5)
You can add a clef at positions other than the first beat of the first bar. For example:
music <- Music() + Meter(2, 4) + Line(c("C3", "D3"), bar = 2) + Clef("F", bar = 2, offset = 1) show(music, "score")
You can use duration notations to specify durations. For example:
durations <- c("q.", "eighth", "quarter..", "16th") music <- Music() + Meter(4, 4) + Line(durations = durations) show(music, "score")
A duration notation can have two parts:
All supported duration types:
duration_types <- gm:::duration_types duration_types$value <- duration_types$value |> lapply(gm:::to_fraction) |> lapply(\(fraction) { if (fraction[2] == 1) fraction[1] else paste(fraction, collapse = "/") }) |> as.character() names(duration_types) <- c("Duration Type", "Abbreviation", "Value") knitr::kable(duration_types)
You can also use duration values to specify durations. For example:
durations <- 1:5 music <- Music() + Meter(5, 4) + Line("C4", durations) show(music, "score")
A valid duration value should be equal to the total length of one or more duration types. For example, 0.5 is equal to the length of eighth; 1.5 is equal to the total length of quarter and eighth; 1.1 is not valid.
You can specify tuplets with more complex duration notations. For example:
durations <- rep("half/3", 3) music <- Music() + Meter(2, 4) + Line(durations = durations) show(music, "score")
Here we use "/3" to divide the half note into three tuplets. In the following example, we divide the half note into two tuplets of different lengths:
durations <- c("half/3", "half/3*(half/quarter)") music <- Music() + Meter(2, 4) + Line(durations = durations) show(music, "score")
Please note that tuplets should come in groups. For example, two half/3 tuplets or four half/3 tuplets cannot form a valid group. And a tuplet group should not cross bar lines.
gm can represent nested tuplets like this:
However, because gm uses MusicXML to represent music internally, but MuseScore cannot handle nested tuplets with MusicXML, we will skip this part.
You can use Meter()
to add a time signature. For example:
music <- Music() + Meter(1, 4) + Meter(2, 4, bar = 2) + Line(c("C4", "E4", "G4")) show(music, "score")
To apply show()
to a Music
object, there must be a time signature at the first bar.
You can add a pickup measure by using arguments actual_number
, actual_unit
, and invisible
. For example:
music <- Music() + Meter(4, 4, actual_number = 1, actual_unit = 4) + Meter(4, 4, bar = 2, invisible = TRUE) + Line(c("A4", "B4", "C5", "D5", "E5")) show(music, "score")
You can use Tempo()
to add a tempo mark. For example:
music <- Music() + Meter(4, 4) + Line(60:67) + Tempo(90) + Tempo(120, bar = 2) + Tempo(200, bar = 2, offset = 2) show(music)
You can add more sophisticated tempo marks by using argument marking
. For example:
music <- Music() + Meter(4, 4) + Line(60:67) + Tempo(90, marking = "Slowly!!") + Tempo(200, offset = 2, marking = "quarter. = quarter") + Tempo(120, bar = 2, marking = "Allegro (quarter = 110-130)") show(music, "score")
In Line()
, we don't provide notes, rests, or chords directly. Instead, we separate the pitches and durations. This feature is convenient for music programming.
However, Music
objects have a data frame $notes
for representing notes. For example:
music <- Music() + Meter(4, 4) + Line(list("C4", NA, c("C4", "E4")), list(1, "quarter", 2)) show(music, "score")
music$notes
The meaning of each column:
line
indicates the row number of the musical line a note belongs to.i
indicates a note's index in the musical line.j
indicates a note's index in a chord.pitch
indicates the pitch notation of a note.midi
indicates the MIDI note number of a note.duration
indicates the duration notation of a note.length
indicates the length of a note's duration.You can tie together two notes with Tie()
. For example:
notes <- Line(c("C4", "C4")) tie <- Tie(1) music <- Music() + Meter(2, 4) + notes + tie show(music, "score")
You can tie together some notes in chords or the whole chords. For example:
chords <- Line(list(c("C4", "E4"), c("C4", "E4"))) tie <- Tie(1, 2) music <- Music() + Meter(2, 4) + chords + tie show(music, "score")
chords <- Line(list(c("C4", "E4"), c("C4", "E4"))) tie <- Tie(1) music <- Music() + Meter(2, 4) + chords + tie show(music, "score")
gm automatically splits cross-bar notes and adds ties. For example:
cross_bar_note <- Line("C4", 4) music <- Music() + Meter(1, 4) + cross_bar_note show(music, "score")
You can add grace notes with Grace()
. For example:
line <- Line(c("A3", "B3", "C4", "D4"), c(0.25, 0.25, 1, 1)) music <- Music() + Meter(2, 4) + line + Grace(1) + Grace(2) show(music)
The first two notes are indicated as grace notes.
gm adds accidentals to notes based on the key. You can change default accidentals with Accidental()
. For example:
accidental <- Accidental("natural", 2) music <- Music() + Meter(2, 4) + Line(c("C4", "C4")) + accidental show(music, "score")
You can change the shape or color of a note with Notehead()
. For example:
notehead <- Notehead(1, shape = "diamond", color = "#FF0000") music <- Music() + Meter(2, 4) + Line(c("C4", "C4")) + notehead show(music, "score")
You can change the stem of a note with Stem()
. For example:
stem <- Stem("none", 1) music <- Music() + Meter(2, 4) + Line(c("C4", "C4")) + stem show(music, "score")
You can add an articulation to a note with Articulation()
. Some examples:
music <- Music() + Meter(4, 4) + Line(c("C4", "D4", "E4", "F4")) + Articulation(">", 1) + Articulation(".", 2) + Articulation("'", 3) + Articulation("-", 4) show(music)
All supported articulations:
articulations <- gm:::articulations names(articulations) <- c("MuseScore", "MusicXML", "Symbol") knitr::kable(articulations)
You can add a fermata to a note with Fermata()
. For example:
music <- Music() + Meter(4, 4) + Line(c("C4", "D4", "E4", "F4")) + Fermata(4, shape = "square") show(music, "score")
You can add a breath mark to a note with Breath()
. For example:
music <- Music() + Meter(4, 4) + Line(c("C4", "D4", "E4", "F4")) + Breath(2) show(music, "score")
You can add an ornament to a note with the following options:
Schleifer()
Mordent()
Trill()
Turn()
Tremolo()
Some examples:
music <- Music() + Meter(7, 4) + Line(c("B4", "C5", "D5", "E5", "F5", "G5", "A5")) + Tremolo(3, 1) + Turn(2, inverted = TRUE) + Mordent(3, long = TRUE) + Trill(4) + Trill(5, 6) + Schleifer(7) show(music)
You can add a slur to notes with Slur()
. For example:
music <- Music() + Meter(4, 4) + Line(60:63) + Slur(1, 4) show(music, "score")
Slurs can cross staffs. For example:
music <- Music() + Meter(4, 4) + Line(c("C4", "D4")) + Line(c("E4", "F4"), offset = 2, as = "staff") + Slur(1, 2, to = 1, to_j = 2) show(music, "score")
You can use Dynamic()
to add dynamic markings. For example:
music <- Music() + Meter(4, 4) + Line(60:67) + Dynamic("p", 1) + Dynamic("mf", 3) + Dynamic("fff", 5) + Dynamic("pp", 7) show(music)
You can use Velocity()
to adjust note loudness more precisely. For example:
pitches <- 74:50 velocities <- seq(5, 127, 5) music <- Music() + Meter(4, 4) + Tempo(200) + Line(pitches, 0.5) for (i in seq_along(velocities)) { music <- music + Velocity(velocities[i], 1, i) } show(music)
You can use Hairpin()
to add crescendo and decrescendo symbols. For example:
music <- Music() + Meter(4, 4) + Line(60:67) + Dynamic("pp", 1) + Dynamic("ff", 8) + Hairpin("<", 2, 7) show(music)
You can use Instrument()
to specify the instrument of a part. For example:
pitches <- c("C4", "D4", "E4", "F4") music <- Music() + Meter(4, 4) + Line(pitches) + Line(pitches, bar = 2) show(music)
instrument_1 <- Instrument(10, 1) instrument_1
instrument_2 <- Instrument(76, 2) instrument_2
music <- music + instrument_1 + instrument_2 show(music)
You can change the sound placement with argument pan
. For example:
path <- "/Applications/MuseScore 3.app/Contents/MacOS/mscore" options(gm.musescore_path = path)
pitches <- c("C4", "D4", "E4", "F4") music <- Music() + Meter(4, 4) + Line(pitches) + Line(pitches, bar = 2) + Line(pitches, bar = 3) + Instrument(1, 1, pan = -90) + Instrument(1, 2, pan = 0) + Instrument(1, 3, pan = 90) show(music)
options(gm.musescore_path = NULL)
Unfortunately, pan
only works in MuseScore 3, while the latest version is 4, as of the time of writing. The two versions have slightly different features. So it’s recommended to install both versions, and temporarily change the path using options()
when needed. For example, in macOS:
path <- "/Applications/MuseScore 3.app/Contents/MacOS/mscore" options(gm.musescore_path = path)
You can use Pedal()
to add pedals. For example, the following are first two bars of Chopin’s nocturne Op.72 No.1:
music <- Music() + Meter(4, 4) + Key(1) + Tempo(60) + Line(c("B4", "G5", "F#5", "E5"), c("8", "h.", "8", "8"), bar = 2) + Grace(1) + Line(rep(c("E2", "B2", "G3", "E3", "C4", "B3"), 4), "q/3", as = "staff") + Clef("F") + Dynamic("p", 1) + Pedal(1, 12) + Pedal(13, 24) show(music)
You can add lyrics by using Lyric()
. For example:
music <- Music() + Meter(4, 4) + Line(60:63) + Lyric("My_love-", 1) + Lyric("-ly", 2) + Lyric("cat_", 3) + Lyric("_", 4) + Lyric("Hey", 1, verse = 2) + Lyric("Jude", 2, verse = 2) show(music, "score")
You can pass MuseScore command line options to export()
and show()
.
For example, you can change score's DPI and margin:
music <- Music() + Meter(4, 4) + Line("C5") show(music, "score", musescore = "-r 400 -T 100")
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.