Dichord orbifold¶
The space of unordered pairs of pitch classes :math:`mathbb{T}^2/mathcal{S}_2` is a Mӧbius strip. Tymoczko, Dmitri. “The geometry of musical chords.” Science 313.5783 (2006): 72-74.
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
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('bokeh')
hv.output(size=180)
defaults = dict(width=300, height=300, padding=0.1)
hv.opts.defaults(
    opts.EdgePaths(**defaults), opts.Graph(**defaults), opts.Nodes(**defaults))
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 = 2,
    pitches = scale.getPitches('C','B'),
    select = None
)
Generator dichords form a Mӧbius strip¶
We can explore the space of dichords and show that it is a Mӧbius strip. For this, I first extract the chord normal order coordinates and move the pitch-class set to 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.
[3]:
# Generate data points and their labels
data = []
names = []
for chord in chord_generator.run():
    data.append(standardSimplex(chord, scale))
    names.append(chord.normalOrderString)
# Plot the T^2/S_2 orbifold
points = hv.Points(data)
labels = hv.Labels({('x', 'y'): data, 'labels': names}, ['x', 'y'], 'labels')
overlay = (points * labels).redim.range(x=(-0.1, 1.1), y=(-0.1, 1.1))
overlay.opts(
    opts.Labels(text_font_size='10pt', yoffset=+.025),
    opts.Points(color='blue', size=5))
[3]:
The resulting plot is similar to the one shown in the Tymoczko, Dmitri paper The geometry of musical chords or Figure 3.6.1 of A Geometry of Music: Harmony and Counterpoint in the Extended Common Practice, by Dmitri Tymoczko.. The only missing points relative to Tymoczko’s plot are those that are identified as the same chord. I manually added those chords closing their normal ordered string between squared brackets to show how to stick together the Mӧbius strip.
[4]:
identified_chords = (
    [1, 0], [1, 2/12], [1, 4/12], [1, 6/12], [1, 8/12], [1, 10/12], [1,1]
)
chord_names = (
    '[<6>]', '[<57>]', '[<48>]', '[<39>]', '[<A2>]', '[<B1>]', '[<0>]'
)
for index in range(len(chord_names)):
    data.append(identified_chords[index])
    names.append(chord_names[index])
# Plot the T^2/S_2 orbifold with identified chords
points = hv.Points(data)
labels = hv.Labels({('x', 'y'): data, 'labels': names}, ['x', 'y'], 'labels')
overlay = (points * labels).redim.range(x=(-0.1, 1.1), y=(-0.1, 1.1))
overlay.opts(
    opts.Labels(text_font_size='10pt', yoffset=+.025),
    opts.Points(color='blue', size=5))
[4]: