Main idea
Thought: Can I prompt students to use what they know about probability distributions and simulation to write their own pieces of stochastic music?
Worry: Depends. Can you work with music in R?
R
Exploring the intersection of probability and music
Duke Stats
2025-08-09

Plenty of applications from the natural and social sciences:
But what about the arts?
AKA: chance or aleatoric music.


Think of each member of a 46-piece string orchestra as a Brownian particle drifting up and down the staff:

“[E]very member of the orchestra is on the honor system.” Leonard Bernstein
Well …it’s the thought that counts.
Thought: Can I prompt students to use what they know about probability distributions and simulation to write their own pieces of stochastic music?
Worry: Depends. Can you work with music in R?
gm package
“grammar of music”
R with a ggplot2-style interface;“generate music”
MuseScore generates sheet music and MIDI playback.
Let’s transcribe it!
We will add layers to this:



"F#5" means the F♯ in the fifth octave on the piano, etc.
(BTW: this plays nice with Quarto off-the-shelf.)
right_hand <- Line(
pitches = list(NA, "E5", "F#5", "D5", "E5", "F#5",
"B5", "G5", "D5",
"E5", "G4",
c("D4", "F#4", "B4"), c("C#4", "F4", "C5"),
c("G3", "C4", "E4"), c("D#4", "G4"), c("C4", "E4")),
durations = c(0.5, 0.5, 0.5, 0.5, 0.5, 0.5,
1, 1, 2,
1, 1,
2, 1,
1.5, 0.5, 1)
)
prelude <- Music() +
Meter(3, 4) +
Tempo(60) +
right_hand
left_hand <- Line(
pitches = c("A2", "E3", "G3", "C4", "E4",
"G4", "C5", NA,
NA, "E2", "E3", "F#3", "G#3",
NA, "A2", "E3", "B3", "G3"),
durations = c(rep(0.5, 7), 2,
rep(0.5, 4), 1,
rep(0.5, 4), 1),
bar = 2, offset = 0.5
)
prelude <- Music() +
Meter(3, 4) +
Tempo(60) +
right_hand +
left_hand +
Clef("F")Note: rests correspond to missing values (NA) in the line.


… and so on
gm packageA ggplot2-style interface for music:
Now, let’s write some crazy music!
pitches <- c("C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B")
octaves <- 1:7
all_pitches <- c("A0", "A#0", "B0",
paste(rep(pitches, length(octaves)),
sort(rep(octaves, length(pitches))),
sep = ""),
"C8")
all_pitches [1] "A0" "A#0" "B0" "C1" "C#1" "D1" "D#1" "E1" "F1" "F#1" "G1" "G#1"
[13] "A1" "A#1" "B1" "C2" "C#2" "D2" "D#2" "E2" "F2" "F#2" "G2" "G#2"
[25] "A2" "A#2" "B2" "C3" "C#3" "D3" "D#3" "E3" "F3" "F#3" "G3" "G#3"
[37] "A3" "A#3" "B3" "C4" "C#4" "D4" "D#4" "E4" "F4" "F#4" "G4" "G#4"
[49] "A4" "A#4" "B4" "C5" "C#5" "D5" "D#5" "E5" "F5" "F#5" "G5" "G#5"
[61] "A5" "A#5" "B5" "C6" "C#6" "D6" "D#6" "E6" "F6" "F#6" "G6" "G#6"
[73] "A6" "A#6" "B6" "C7" "C#7" "D7" "D#7" "E7" "F7" "F#7" "G7" "G#7"
[85] "A7" "A#7" "B7" "C8"
Sample the pitches with replacement:
set.seed(8675309)
line1 <- Line(
pitches = sample(all_pitches, 64, replace = TRUE),
durations = .25
)
line2 <- Line(
pitches = sample(all_pitches, 64, replace = TRUE),
durations = .25
)
kitten <- Music() +
Meter(4, 4) +
Tempo(120) +
line1 +
line2 +
Dynamic("p", 1) +
Dynamic("ffff", 64) +
Hairpin("<", 2, 63)
It’s a time series!

Game:
From Nierhaus’ Algorithmic Composition (2009 Springer):

A first-order Markov chain on the C minor scale is described by its transition probabilities: given the note we’re on right now, what are the probabilities for the next note to come?
Loads of options to explore:

Take an existing piece of music and “add noise.”
So this:
\[ \mathbf{y}=f(\mathbf{x})+\boldsymbol{\varepsilon}, \]
only…it’s music?

(John, please don’t forget to lower the volume on this.)
gm handle any Hz, and not just the discrete pitches of the Western system?gm package is so much fun to play with!