[1]:
import automuse
import automuse.chord as chord
import automuse.scale as scale
import automuse.modes as modes

Constructing the Circle

The mythical Circle of Fifths, often found in introductory music theory textbooks, highlights some interesting relation in music. This notebook seeks to explore these.

To construct the circle, let us keep counting fifths, beginning at $:nbsphinx-math:`mathrm{C}`$:

[2]:
from automuse import reach
[ ]:
def count_fifths(base: str, length: int):
    accumulated: list[str] = []
    for _ in range(length):
        accumulated.append(base)
        base = reach(base, "perfect 5")
    return accumulated
[4]:
exterior_ring: list[str] = count_fifths("C0", 13)
print(f"Exterior ring: {exterior_ring}")
Exterior ring: ['C0', 'G0', 'D1', 'A1', 'E2', 'B2', 'F#3', 'C#4', 'G#4', 'D#5', 'A#5', 'F6', 'C7']

Conveniently, counting notes this way gives all 12 notes of an octave, with the 13th note coming back to \(\text{C}\). These 12 notes form a cycle.

Recall that A is the submediant of C; consequently the Am scale is the relative minor of CM. Let us count another 12 notes, this time starting with A:

[5]:
submediant_of_C = scale.scale("C0", modes.MAJOR)[5]
print(f"Submediant of C0 on CM is {submediant_of_C}")
interior_ring: list[str] = count_fifths(submediant_of_C, 13)
print(f"Interior ring: {interior_ring}")
Submediant of C0 on CM is A0
Interior ring: ['A0', 'E1', 'B1', 'F#2', 'C#3', 'G#3', 'D#4', 'A#4', 'F5', 'C6', 'G6', 'D7', 'A7']

To form the circle of fifth, stack these cycles on top of each other. This is so very isomorphic.

1a5d4a9e0a064c3095a6f4b87555a49e

Note that this mechanical construction is not correct: the actual circle of fifths uses a mix of sharps and flats so that intervals between neighbouring notes are always fifths’. In this circle, however, the note before F is A# (as opposed to Bb), so the interval is in reality a diminished sixth.

[6]:
from automuse import name_intervals
name_intervals(exterior_ring)
[6]:
['perfect 5',
 'perfect 5',
 'perfect 5',
 'perfect 5',
 'perfect 5',
 'perfect 5',
 'perfect 5',
 'perfect 5',
 'perfect 5',
 'perfect 5',
 'diminished 6',
 'perfect 5']

Applying the Circle

The circle of fifth has many uses. First of all, it matches every chord to its relative major: for every note in the exterior ring, its major scale has the same notes as the minor scale constructed with its interior neighbour:

[7]:
chord.chord("C", modes.MAJOR)
[7]:
['C0', 'E0', 'G0']
[8]:
for i in range(len(exterior_ring)):
    assert automuse.same_class(
        scale.scale(exterior_ring[i], modes.MAJOR),
        scale.scale(interior_ring[i], modes.MINOR)
    )

Continue for more uses of the circle.

Usage: Neighbouring Scales

The circle of fifths is a neat way to arrange scales. The closest (in \(\mathscr{l}_1\)) neighbours of a scale are its neighbours on the circle: for example, CM and GM differ by exactly 1 note which differs by exactly 1 semitone; the same is true for GM and DM.

[9]:
print(sorted(scale.scale("C", modes.MAJOR)))
print(sorted(scale.scale("G", modes.MAJOR)))
print(sorted(scale.scale("D", modes.MAJOR)))
['A0', 'B0', 'C0', 'D0', 'E0', 'F0', 'G0']
['A0', 'B0', 'C1', 'D1', 'E1', 'F#1', 'G0']
['A0', 'B0', 'C#1', 'D0', 'E0', 'F#0', 'G0']

Geometry

Coincidentally, neighbours of a note are in its major scale: its left neighbour the subdominant (\(\hat{4}\)), its right neighbour the dominant (\(\hat{5}\)), and its interior neighbour the submediant (\(\hat{6}\)).

49e115e12c4b4d8baf91a7e5e677841e

Because chords are constructed from scale degrees, chords can be expressed on the circle as polygons. For example, connecting notes on a C major triad results in a triangle; rotating this triangle clockwise by \(30\degree\) gives the G major triad.

0b52b6f945c549d4a13f9e704bdabe08

Tools of this kind are common in music. Another good example is the Tonnetz for visualising Neo-Riemannian transforms. The Tonnetz which will not be explained here.

Usage: Sharps and Flats

Another interesting pattern: starting at C and counting clockwise, each subsequent scale has one more sharp. Going down from C has the same effect: each subsequent scale has one more flat.

As a result, each note on the circle corresponds to a number of sharps and flats. These accidentals are often notated right after the staff.

[10]:
for base in count_fifths("C0", 12):
    print(len(
        [x for x in scale.scale(base, modes.MAJOR)
         if "#" in x]
    ))
0
1
2
3
4
5
5
5
4
3
2
1