Trichord orbifold

*… the space of n-note chords is an n-dimensional prism whose simplical … faces are glued together with a twist, and whole remaining boundaries act like mirrors. Dmitri Tymoczko, A Geometry of Music: Harmony and Counterpoint in the Extended Common Practice, Oxford University Press, 2011, page 410.

Introduction

This notebook is a demonstration of Orbichord, a project to explore topologically non-trivial space of music chords that are global-quotient orbifolds, see references:

  • Project page: https://orbichord.github.io

  • Project Github: https://github.com/orbichord/orbichord

  • Tymoczko, Dmitri. “The geometry of musical chords.” Science 313.5783 (2006): 72-74.

  • Callender, Clifton, Ian Quinn, and Dmitri Tymoczko. “Generalized voice-leading spaces.” Science 320.5874 (2008): 346-348.

  • Dmitri Tymoczko, A Geometry of Music: Harmony and Counterpoint in the Extended Common Practice, Oxford University Press, 2011.

Orbichord comes from combining the words orbifold and chord. It is a collection of python modules build on top of music21 project.

Importing modules

Import music and graphite modules

[1]:
# Import music modules
import itertools
from music21.scale import ChromaticScale
from orbichord.chordinate import standardSimplex
from orbichord.generator import Generator

# Import graphic modules
import holoviews as hv
from holoviews import opts

hv.extension('plotly')
hv.output(size=180)

Data type cannot be displayed: application/vnd.holoviews_load.v0+json

Configure an orbichord generator

Create a dichord generator using a chromatic scale starting from C pitch. By default, chords are identified by a normal ordered string, resulting in the space chord defined by a collection of pitch-class sets. I will also be using the normal ordered string to label the dichords to avoid any confusion because of the enharmonic equivalance.

[2]:
scale = ChromaticScale('C')

chord_generator = Generator(
    dimension = 3,
    pitches = scale.getPitches('C','B'),
    select = None
)

Plotting 3-node chord space

We can directly plot the space of trichords and show it is fundamentally a prism. For this, I compute standard simplex using the algorithm described in figure B2, page 404 in Dmitri Tymoczko, A Geometry of Music. Moreover, I also applied affine transformation over the simplex coordinates defined as follow:

\[\begin{split}\begin{align} x' &= (x + y + z)/12 \\ y' &= (y - x)/12 \\ z' &= (z - y)/12 \end{align}\end{split}\]
[3]:
# Generate data points and their labels
points = []
for chord in chord_generator.run():
    points.append(standardSimplex(chord, scale))
# Plot the T^3/S_3 orbifold
hv.Scatter3D(points).opts(padding=0.05)
[3]:
Drawing...

The resulting plot is similar to the one shown on page 86, figure 3.8.2 in Dmitri Tymoczko, A Geometry of Music: Harmony and Counterpoint in the Extended Common Practice, Oxford University Press, 2011.

Slicing the prism

We can simplify the plotting of the prism by slicing it horizontally, as it is done on page 89, figure 3.8.4 in Dmitri Tymoczko, A Geometry of Music: Harmony and Counterpoint in the Extended Common Practice, Oxford University Press, 2011.

For that, we will change of plotting backend first.

[4]:
hv.extension('bokeh')
hv.output(size=180)
[5]:
# Generate data points and their labels
data = {}
names = {}
for chord in chord_generator.run():
    x, y, z = standardSimplex(chord, scale)
    data.setdefault(x, []).append([y, z])
    names.setdefault(x, []).append(chord.normalOrderString)

# Define how to plot the slice of the prism
def draw_slice(index):
    points = hv.Points(data[index])
    labels = hv.Labels({('x', 'y'): data[index], 'labels': names[index]}, ['x', 'y'], 'labels')
    overlay = (points * labels).redim.range(x=(-0.1, 1.1), y=(-0.1, 1.1))
    return overlay.opts(
        opts.Labels(text_font_size='10pt', yoffset=+.025),
        opts.Points(color='blue', size=5, xlabel='y', ylabel='z'))

# Create a holomap with all the slides
slices = {slice: draw_slice(slice) for slice in sorted(names.keys())}
hv.HoloMap(slices, kdims='x')
[5]:

The only missing points relative to Tymoczko’s plot are those that are identified as the same chord. For example, the chord the chord with notes {F, F, D} with \(x = 0\) is missing. This is because its normal ordered string is <25> that is also identify the chord {D, D, F} that can be found in slide with coordinate \(x = 0.75\).