Complete Guide to gm

library(gm)

There are two interpretations of the package name gm:

  1. grammar of music
  2. generate music

They correspond to two functionalities of the package:

  1. a language for music representation
  2. generation of music scores and audio files

Let’s start with a quick example.

Example

music <- 
  Music() +
  Meter(4, 4) +
  Line(c("C5", "D5", "E5", "F5"))
  
show(music)

Let’s go through the code line by line:

  1. music <- defines a variable.
  2. Music() initializes a Music object.
  3. + Meter(4, 4) adds a 4/4 time signature.
  4. + Line(c("C5", "D5", "E5", "F5")) adds four notes.
  5. 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.

Installation

Install gm:

install.packages("gm")

Install MuseScore. MuseScore is open source and free notation software. Internally, gm uses MuseScore to generate music.

Configuration

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:

  1. Open .Renviron file.
  2. Add environment variable MUSESCORE_PATH=<path to MuseScore>.
  3. Restart R session.

For example, the environment variable is like

Music

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:

  1. Initialize a Music object with Music().
  2. Add components to it with +.
  3. Display the music with 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
#> 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 Line

Musical lines are the most basic units of music in gm. You can create a musical line with Line().

Pitches and Durations

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.

Musical Line Insertion

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.

Multiple Musical Lines

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.

Musical Line Hierarchy

There is a hierarchy of musical lines:

  1. part
  2. staff
  3. voice
  4. segment

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.

Musical Line Representation

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.

Pitch

Pitch Notation

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

  1. a tone name which can be C, D, E, F, G, A, or B,
  2. an optional accidental which can be -, --, #, or ##, and
  3. a number between 0 and 9 that indicates the pitch’s octave.

MIDI Note Number

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)