You can download the raw source code for these lecture notes here.
Below, you can see two self-similarity matrices for Aphex Twin’s ‘Avril 14th’. Listen to the piece together and try to explain the patterns you see in the matrices.
library(tidyverse)
library(spotifyr)
library(compmus)
Last week, we used several custom functions from to work with the Spotify API:
get_tidy_audio_analysis to load audio analyses from
Spotify, one track at a timecompmus_normalise to normalise audio features using
common techniques, including:
manhattaneuclideanchebyshevcompmus_long_distance to compare to series of audio
features against each other using common distance metrics, including:
manhattanaitchisoneuclideancosineangularThis week, we will use a few new custom functions.
compmus_align aligns two levels of structure with each
other, e.g., Spotify segments with
sectionsbarsbeatstatumscompmus_summarise helps to summarise features within
higher levels of structure, including:
meanacentre [Aitchison centre, for use with chroma or
Aitchison distances]rms [root mean square]max| Domain | Normalisation | Distance | Summary Statistic |
|---|---|---|---|
| Non-negative (e.g., chroma) | Manhattan | Manhattan | mean |
| Aitchison | Aitchison centre | ||
| Euclidean | cosine | root mean square | |
| angular | root mean square | ||
| Chebyshev | [none] | max | |
| Full-range (e.g., timbre) | [none] | Euclidean | mean |
| Euclidean | cosine | root mean square | |
| angular | root mean square |
The following examples from Andre Hazes’s ‘Bloed, Zweet en Tranen’
highlight how to use these functions. If you are following your DataCamp
exercises carefully and are looking to develop more advanced R skills,
notice the use of the purrr:map() function here. But you
can also use this code as a template: the lines you need to change to
make your own cepstrograms are marked.
bzt <-
get_tidy_audio_analysis("5ZLkc5RY1NM4FtGWEd6HOE") |> # Change URI.
compmus_align(bars, segments) |> # Change `bars`
select(bars) |> # in all three
unnest(bars) |> # of these lines.
mutate(
pitches =
map(segments,
compmus_summarise, pitches,
method = "rms", norm = "euclidean" # Change summary & norm.
)
) |>
mutate(
timbre =
map(segments,
compmus_summarise, timbre,
method = "rms", norm = "euclidean" # Change summary & norm.
)
)
We can use compmus_gather_timbre much like
compmus_gather_chroma last week to yield a cepstrogram.
This code should work as a template for you with no changes
necessary.
bzt |>
compmus_gather_timbre() |>
ggplot(
aes(
x = start + duration / 2,
width = duration,
y = basis,
fill = value
)
) +
geom_tile() +
labs(x = "Time (s)", y = NULL, fill = "Magnitude") +
scale_fill_viridis_c() +
theme_classic()
Try different levels of summarisation: section, bar, beat, and tatum. Which one seems to be the ‘sweet spot’ where patterns are most visible?
Try different combinations of norms, distances, and summary statistics. Which seem to give the clearest visualisation?
Once you are happy with your choices in steps 1 and 2, make cepstrograms for several other tracks from André Hazes, and look for timbre components where there are clear changes (e.g., c02 in ‘Bloed, Zweet en Tranen’). Listen to these tracks and follow along with the cepstrograms. Can you think of words to describe what is changing in the music when you see sharp changes in the cepstrogram? Could you give any of Spotify’s timbre components a name?
The function compmus_self_similarity is a wrapper around
compmus_long_distance from last week, for the case where
the distances are computed form the same track.
bzt |>
compmus_self_similarity(timbre, "cosine") |>
ggplot(
aes(
x = xstart + xduration / 2,
width = xduration,
y = ystart + yduration / 2,
height = yduration,
fill = d
)
) +
geom_tile() +
coord_fixed() +
scale_fill_viridis_c(guide = "none") +
theme_classic() +
labs(x = "", y = "")
pitches). Adjust your summary and norm (from the
pitches line of the previous breakout), as well as the
distance metric, to get the best visualisation.