There are two interpretations of the package name gm:
They correspond to two functionalities of the package:
Let’s start with a quick example.
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:
Add an articulation:
music <- music + Articulation(">", 1)
show(music)
Add a pedal:
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:
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
#> Music
#>
#> $meters
#> # A tibble: 1 × 6
#> bar number unit actual_number actual_unit invisible
#> <int> <int> <int> <int> <int> <lgl>
#> 1 1 4 4 4 4 FALSE
#>
#> $notes
#> # A tibble: 4 × 7
#> line i j pitch midi duration length
#> <int> <int> <int> <chr> <int> <chr> <dbl>
#> 1 1 1 NA C5 72 NA 1
#> 2 1 2 NA D5 74 NA 1
#> 3 1 3 NA E5 76 NA 1
#> 4 1 4 NA F5 77 NA 1
#>
#> $lines
#> # A tibble: 1 × 7
#> part staff voice segment bar offset name
#> <int> <int> <int> <int> <int> <dbl> <chr>
#> 1 1 1 1 1 1 0 NA
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
#> # A tibble: 3 × 7
#> part staff voice segment bar offset name
#> <int> <int> <int> <int> <int> <dbl> <chr>
#> 1 1 1 1 1 1 0 a
#> 2 1 1 2 1 1 0 b
#> 3 1 2 1 1 1 2 c
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:
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:
To transpose them up by a fifth, we can simply add 7 to them:
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:
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))
}
#> Key C- Major (A- Minor)
#> Key G- Major (E- Minor)
#> Key D- Major (B- Minor)
#> Key A- Major (F Minor)
#> Key E- Major (C Minor)
#> Key B- Major (G Minor)
#> Key F Major (D Minor)
#> Key C Major (A Minor)
#> Key G Major (E Minor)
#> Key D Major (B Minor)
#> Key A Major (F# Minor)
#> Key E Major (C# Minor)
#> Key B Major (G# Minor)
#> Key F# Major (D# Minor)
#> Key C# Major (A# Minor)
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:
All supported clefs:
Clef("G")
#> Treble Clef
Clef("G", line = 1)
#> French Clef
Clef("G", octave = 1)
#> Octave Up Treble Clef
Clef("G", octave = -1)
#> Octave Down Treble Clef
Clef("F")
#> Bass Clef
Clef("F", line = 3)
#> Baritone F-Clef
Clef("F", line = 5)
#> Subbass Clef
Clef("F", octave = 1)
#> Octave Up Bass Clef
Clef("F", octave = -1)
#> Octave Down Bass Clef
Clef("C")
#> Alto Clef
Clef("C", line = 1)
#> Soprano Clef
Clef("C", line = 2)
#> Mezzo-Soprano Clef
Clef("C", line = 4)
#> Tenor Clef
Clef("C", line = 5)
#> Baritone C-Clef
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 Type | Abbreviation | Value |
---|---|---|
maxima | m | 32 |
long | l | 16 |
breve | b | 8 |
whole | w | 4 |
half | h | 2 |
quarter | q | 1 |
eighth | 8 | 1/2 |
16th | 16 | 1/4 |
32nd | 32 | 1/8 |
64th | 64 | 1/16 |
128th | 128 | 1/32 |
256th | 256 | 1/64 |
512th | 512 | 1/128 |
1024th | 1024 | 1/256 |
You can also use duration values to specify durations. For example:
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
#> # A tibble: 4 × 7
#> line i j pitch midi duration length
#> <int> <int> <int> <chr> <int> <chr> <dbl>
#> 1 1 1 NA C4 60 NA 1
#> 2 1 2 NA NA NA quarter 1
#> 3 1 3 1 C4 60 NA 2
#> 4 1 3 2 E4 64 NA 2
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:
MuseScore | MusicXML | Symbol |
---|---|---|
accent | accent | > |
staccato | staccato | . |
staccatissimo | staccatissimo | ’ |
tenuto | tenuto | - |
tenuto-staccato | detached-legato | -. |
marcato | strong-accent | ^ |
scoop | scoop | NA |
plop | plop | NA |
doit | doit | NA |
fall | falloff | NA |
stress | stress | , |
unstress | unstress | u |
soft accent | soft-accent | <> |
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 an ornament to a note with the following options:
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 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 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
#> Glockenspiel
#>
#> * to be added to the part containing Line 1
instrument_2 <- Instrument(76, 2)
instrument_2
#> Pan Flute
#>
#> * to be added to the part containing Line 2
music <- music + instrument_1 + instrument_2
show(music)
You can change the sound placement with argument pan
.
For example:
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)
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)