Four-part harmony, read from a marker's source
Every student of harmony writes the same kind of exercise. Four voices, soprano, alto, tenor and bass, move from chord to chord, and a teacher marks the result in red. The marks are old. Musica enchiriadis, a treatise of about 895, is the first document to describe organum, the earliest written polyphony, and in its simplest kind a chant is doubled a fourth or a fifth below, the two voices moving in parallel and often beginning and ending on a unison. By about 1300 a treatise long ascribed to Johannes de Garlandia forbade two perfect fifths in a row, and by the middle of the fifteenth century the prohibition was settled. Teachers have marked it ever since.
The classroom has two great sources. In 1725 Johann Joseph Fux published his Gradus ad Parnassum in Vienna, a Latin dialogue in which a master, Aloysius, who stands for Palestrina, teaches a student, Josephus, who stands for Fux himself, counterpoint one species at a time. Haydn taught himself from it, working through every exercise, and Mozart and Beethoven knew it. The second source is Bach's four-part chorales, collected after his death and printed by Breitkopf between 1784 and 1787: 371 pieces, of which 348 are independent harmonisations. Students have learned four-part writing by imitating them ever since.
The harmony library for DKE, the Deterministic Knowledge Engine, writes the rules down in DKE Python, and this essay teaches the subject by reading them. You record an exercise as facts: the voices, the key, the pitch of each note. The library's rules then mark it as a teacher would, and each mark names the notes it rests on. Correct a note, and the marks it supported are withdrawn. Every program below runs as shown once the library's source file has been compiled into a store, and every output is copied from a run.
1. A piece as facts
A note needs a number before a rule can compare it. The library uses the MIDI note number, from the MIDI standard of 1983: one number to a semitone, with 69 for the A above middle C at 440 hertz, which puts middle C at 60. Scientific pitch notation names that C as C4, and this essay uses its names. So 72 is the C an octave above middle C, and 55 the G below it.
An exercise is facts about four kinds of thing: a voice, a key, a degree of the key and a note. A note names its voice, its beat, its pitch and the key it is read in:
class Note:
voice: string
beat: int
pitch: int
key: stringA beat here is one chord, and the chords are numbered in order. satb() writes the four voices of a chorale with their ranges, key() writes C major and its seven degrees, and chord() writes one chord's four notes from the bass up. This is a student's exercise in C major, with mistakes in it:
import harmony
harmony.satb()
harmony.key("C", 0, "major")
harmony.chord(1, "C", 48, 55, 64, 72)
harmony.chord(2, "C", 50, 57, 66, 74)
harmony.chord(3, "C", 35, 55, 62, 67)
harmony.chord(4, "C", 48, 55, 64, 72)
harmony.chord(5, "C", 45, 60, 69, 64)
harmony.chord(6, "C", 43, 59, 65, 74)
harmony.chord(7, "C", 48, 60, 64, 72)
ns = list_subjects(harmony.Note)
print(len(ns))28Twenty-eight notes, seven chords of four. The ranges satb() writes are a convention, bass from E2 to C4, tenor C3 to G4, alto G3 to D5 and soprano C4 to G5, and textbooks differ from one another by a note or two.
2. What a note knows
A rule cannot hear a chord. It can compare numbers, so the library first works out, for every note, what the other voices sound on its beat. The voices are ordered from the bottom by their place, 1 for the bass:
@rule
def sounding_1():
for n in Note, m in Note:
if m.beat == n.beat and m.place == 1:
n.p1 = m.pitchp1 is the bass's pitch on the note's beat, and two more rules fill in p2 and p3 for the voices at places 2 and 3. From those, computed fields give the note's pitch class and its interval above each voice:
pc: int = pitch % 12
i1: int = (pitch - p1) % 12Taking the difference modulo 12 throws the octaves away. That is the oldest equivalence in music: a C and the C an octave above it share a name in every scale. So 7 is a fifth whether the two voices are seven semitones apart or nineteen, and 0 is a unison or any number of octaves. Teachers count a twelfth followed by a fifth as consecutive fifths for the same reason. In the first chord:
import harmony
for name in ["tenor1", "alto1", "soprano1"]:
n = harmony.Note(name)
i = n.i1
print(name, i.value)tenor1 7
alto1 4
soprano1 0Above the bass's C, the tenor's G is a fifth, the alto's E a major third, and the soprano's C two octaves.
3. Consecutive fifths and octaves
Here is the rule a teacher marks most often:
@rule
def fifths_over_1():
for a in Note, c in Note, m in Note:
if a.place > 1 and c.voice == a.voice and c.beat == a.nextbeat and m.place == 1 and m.beat == a.beat and a.i1 == 7 and c.i1 == 7 and a.pitch != c.pitch and a.p1 != c.p1:
Fifths.a.m = TrueRead it one premise at a time. a is a note above the bass, c is the note of the same voice on the next beat, and m is the bass under a. Both a and c lie a fifth above the bass, and both voices move: a.pitch != c.pitch for the upper voice and a.p1 != c.p1 for the bass. Two more rules ask the same question above the voices at places 2 and 3, and three more ask it for octaves, with 0 where this one has 7. The conclusion is a relation between two notes, Fifths.a.m, which can be asked about like any other fact.
The usual explanation of the rule is independence. Two voices moving in parallel perfect consonances sound like one voice doubled, so a four-part texture loses a part, and the organum the rule replaced was exactly that sound. Fifths in contrary motion, a fifth moving to a twelfth, are generally avoided too, and the rule marks them, since within the octave their intervals are the same. Some theorists object as well to a perfect fifth moving to a diminished one, an unequal fifth, and some only to one direction of it; the rule does not mark it, since it asks for a perfect fifth on both beats. A voice that holds its note while the other leaps makes no consecutives, which is what the last two premises are for.
The exercise's marks:
import harmony
for f in harmony.faults():
print(f)consecutive fifths: bass and soprano, beats 5 to 6
consecutive fifths: bass and tenor, beats 1 to 2
consecutive octaves: bass and soprano, beats 1 to 2
crossing: soprano below alto, beat 5
outside the key: alto, beat 2
range: bass too low, beat 3From the first chord to the second every voice rises a step, so the bass and tenor move from a fifth to a fifth, and the bass and soprano from an octave to an octave. Beats 5 and 6 put fifths between the outer voices, beat 5 has the soprano under the alto, beat 3 takes the bass down to B1, below its range, and beat 2's F sharp is not in C major.
Every mark answers why:
import harmony
w = why(harmony.Fifths.tenor1.bass1)
for c in w:
print(str(c.path) + " = " + str(c.value))harmony.Fifths.tenor1.bass1 = True
harmony.Note.tenor1.pitch = 55
harmony.Note.bass1.pitch = 48
harmony.Note.tenor2.pitch = 57
harmony.Note.bass2.pitch = 50
harmony.Note.tenor1.i1 = 7
harmony.Note.tenor2.i1 = 7That is the mark and the pitches and intervals it compared. The full answer is longer, since it names every fact the rule read, down to the voices' places, and you can check the mark by reading it: G over C, then A over D.
4. A mark is not a verdict
The rules are a classroom's, and composers have always kept them loosely. Brahms collected passages in which other composers wrote consecutive fifths and octaves, from Beethoven, Méhul, Caldara and others, and Heinrich Schenker published the collection with a commentary of his own in 1933 as Oktaven und Quinten u. A. Debussy opens La cathédrale engloutie, from his first book of Préludes of 1909 and 1910, with chords moving in parallel fifths. Moving chords in parallel like that is called planing, and it chooses the doubled sound the rule exists to prevent.
The exercise has a mark of the same kind: beat 2's F sharp. A D major chord in C that moves on to G is the dominant of the dominant, and a composer writes its F sharp on purpose. The library marks it all the same, because the rule as a teacher states it says that F sharp is not in the key. A mark is the rule applied exactly. Whether it is a fault is the reader's call.
5. What a chord is
In 1722 Jean-Philippe Rameau published his Traité de l'harmonie in Paris, and with it two ideas: a chord has a fundamental bass, its root, and C, E and G make the same chord whichever of them is lowest. E, G and C is its first inversion, and G, C and E its second. The library reads a chord the way those ideas suggest, from the intervals above its bass:
@rule
def major_first():
for b in Note, x in Note, y in Note:
if b.place == 1 and x.beat == b.beat and x.i1 == 3 and y.beat == b.beat and y.i1 == 8:
b.chord = "major, first inversion"A minor third and a minor sixth above the bass make a major triad with its third in the bass. Figured bass, the shorthand of the continuo players from about 1600 to 1750, wrote the same chord as a 6 under the bass note, a second inversion as 6/4, and the inversions of a seventh chord as 6/5, 4/3 and 4/2. The library knows major, minor and diminished triads in all three positions, a major or minor triad with its fifth left out, and the dominant seventh in root position, with its fifth left out and in its three inversions:
import harmony
for b in range(1, 8):
print(b, harmony.readings(f"bass{b}"))1 ['major']
2 ['major']
3 ['major, first inversion']
4 ['major']
5 ['minor']
6 ['dominant seventh', 'major']
7 ['major, fifth omitted']Beat 3 is G major over its B, and beat 7 is C major with no G, a common way to end. Beat 6 has two readings. G, B, D and F make a dominant seventh, and the chord also contains G, B and D, so the rule for a major triad, which asks only for a major third and a fifth above the bass, holds too. Each rule reads exactly the intervals it names, and a chord takes every reading it contains. A chord of no shape the rules know, such as an augmented triad, gets none.
6. Correcting, and disagreeing
The student fixes beat 2 by writing it again, with the tenor and soprano moving against the bass:
import harmony
harmony.chord(2, "C", 50, 54, 66, 69)
for f in harmony.faults():
print(f)consecutive fifths: bass and soprano, beats 5 to 6
crossing: soprano below alto, beat 5
outside the key: alto, beat 2
outside the key: tenor, beat 2
range: bass too low, beat 3chord() writes under one source, harmony, so writing a beat again replaces its notes, and every mark they supported is withdrawn. The fifths and octaves of beats 1 to 2 are gone, and nothing had to be told to remove them: they rested on the old pitches, and the old pitches are no longer in force.
The new chord brings a mark of its own. The tenor now has an F sharp too, so the chord doubles it, and F sharp is the leading note of G, the key this chord leads to. A teacher would mark the doubled leading note. The library does not check doubling, and section 10 lists what else it leaves out. It marks what it knows, which is two notes outside the key.
A teacher who disagrees with the student writes a note under another source:
import harmony
update(harmony.Note.alto2.pitch, 62, "teacher")
for f in harmony.faults():
print(f)
print(harmony.unsettled())consecutive fifths: bass and soprano, beats 5 to 6
crossing: soprano below alto, beat 5
outside the key: tenor, beat 2
range: bass too low, beat 3
['note alto2']The teacher's D does not replace the student's F sharp. Both are held, and unsettled() names the note so that the disagreement is not lost. Every rule reasons from both values, with two exceptions. A sum is not drawn from a part bound to it twice, as section 7 shows. And a mark that asks for something to be missing, as "outside the key" asks that no degree of the key match the note, holds only when no value on record supplies the missing thing. The alto's mark is withdrawn while the D stands beside the F sharp, and settling the matter is left to a person, who removes one of the two.
7. Rhythm as facts
Rhythm is arithmetic too. The library counts it in a unit you choose, and in sixteenths a bar of four beats is 16 long, with a beat of 4. The tones that start in a bar should fill it exactly:
@rule
def bar_filled():
for b in Bar, t in Tone:
if t.onset >= b.start and t.onset < b.end and absent(b.disputed):
b.filled = sum(t.duration)Its last premise holds the sum back while a tone is bound to the bar twice, as a second source giving a tone's duration, even the same duration, would bind it: the sum would add the tone twice.
A tone that starts off a beat and lasts past the next one is syncopated:
offbeat: int = (onset - barstart) % pulse
nextpulse: int = onset - (onset - barstart) % pulse + pulse@rule
def syncopated():
for t in Tone:
if t.offbeat > 0 and t.ends > t.nextpulse:
t.syncopated = TrueA melody of eleven tones over three bars:
import harmony
harmony.bars(3, 16, 4)
harmony.melody([4, 4, 8, 2, 4, 2, 8, 4, 4, 4, 6])
for f in harmony.rhythm_faults():
print(f)across the bar line: t11
bar m3: 18 of 16
syncopated: t5The fifth tone is a quarter note that starts half a beat late, on the third sixteenth of its beat, and is held over the next beat: short, long, short, the figure every syncopation exercise begins with. The last tone is two sixteenths too long for its bar. In written music a tone that crosses a bar line is written as two notes tied, so the library marks it twice, once for the bar and once for the line.
Bars may differ in length, which is how a change of metre is written. Here a fourth bar of three beats is added, 12 long, with a melody that fills it:
import harmony
update(harmony.Bar.x4.start, 48, "me")
update(harmony.Bar.x4.length, 12, "me")
update(harmony.Bar.x4.pulse, 4, "me")
harmony.melody([4, 4, 8, 2, 4, 2, 8, 4, 4, 4, 4, 4, 4, 4])
print(harmony.rhythm_faults())['syncopated: t5']8. Tuning, the arithmetic under the notes
frequency turns a note number into hertz:
return a4 * 2.0 ** ((midi - 69) / 12)Each semitone multiplies the frequency by the twelfth root of two, so twelve of them double it and every semitone is the same size. That is equal temperament. Zhu Zaiyu, a prince of the Ming dynasty, calculated it accurately in 1584, and Simon Stevin worked it out in the Low Countries about 1605, in a manuscript that was not printed until 1884. The number for A is a convention: France fixed A at 435 hertz by law in 1859, an international conference recommended 440 in 1939, and the International Organization for Standardization recommended 440 in 1955 and made it the standard ISO 16 in 1975.
import harmony
print(harmony.frequency(69))
print(harmony.frequency(60))
print(harmony.frequency(69, 435.0))
print(harmony.cents(3 / 2))
print(harmony.cents(5 / 4))440.0
261.6255653005986
435.0
701.9550008653874
386.3137138648348cents measures an interval on Alexander Ellis's scale of 1885: 1200 cents to the octave, so 100 to the equal-tempered semitone. A fifth tuned pure, a frequency ratio of 3 to 2, is 701.955 cents, almost two cents wider than the tempered fifth's 700. A pure major third, 5 to 4, is 386.3 cents, almost fourteen narrower than the tempered third's 400. No scale of pure intervals can avoid an error somewhere. Twelve pure fifths overshoot seven octaves by the Pythagorean comma, and four pure fifths overshoot a pure major third two octaves up by the syntonic comma:
import harmony
print(harmony.cents(531441 / 524288))
print(harmony.cents(81 / 80))23.460010384649014
21.50628959671478Equal temperament takes a twelfth of the Pythagorean comma, 1.955 cents, from every fifth, so that twelve tempered fifths land exactly on the seventh octave and every key sounds alike, and it leaves every major third wide. A piano tuner hears the error as beating. Two tones whose harmonics nearly coincide pulse at the difference of their frequencies. The third harmonic of A3 and the second of E4 would be a single frequency if the fifth were pure, and because it is tempered they beat slowly:
import harmony
a3 = harmony.frequency(57)
e4 = harmony.frequency(64)
print(a3, e4)
print(harmony.beating(a3, 3, e4, 2))220.0 329.6275569128699
0.7448861742601594That is about three beats in four seconds. Tuning guides give the A3 to E4 fifth a beat a little under once a second, and a tuner sets the temperament by timing slow beats like these against a metronome.
9. Pitch classes, sets and rows
The arithmetic modulo 12 of section 2 is also the foundation of twentieth-century music theory. Set theory treats a chord as a set of pitch classes, and two sets as one set class when one is a transposition or an inversion of the other. A set class is named by its prime form, its most compact arrangement, starting on 0:
import harmony
print(harmony.prime_form([0, 4, 7]))
print(harmony.prime_form([9, 0, 4]))
print(harmony.interval_vector([0, 4, 7]))
print(harmony.prime_form([0, 1, 4, 6]), harmony.prime_form([0, 1, 3, 7]))
print(harmony.interval_vector([0, 1, 4, 6]), harmony.interval_vector([0, 1, 3, 7]))[0, 3, 7]
[0, 3, 7]
[0, 0, 1, 1, 1, 0]
[0, 1, 4, 6] [0, 1, 3, 7]
[1, 1, 1, 1, 1, 1] [1, 1, 1, 1, 1, 1]C major and A minor have the same prime form: a major triad turned upside down is a minor triad, so to set theory they are one class. The interval vector counts the pairs of notes at each interval class from 1 to 6, so a major triad has one minor third, one major third and one fifth, which class 5 counts together with the fourth it inverts to. The last two sets are the two all-interval tetrachords, each holding every interval class exactly once. They share a vector without being transpositions or inversions of each other, and Allen Forte's numbering marks such a pair with a Z, as 4-Z15 and 4-Z29.
Most compact has two published definitions. Forte's book of 1973 packs a set towards its start, and John Rahn's of 1980 packs it towards its end. They agree for all but six set classes, and prime_form gives both:
import harmony
for s in [[0, 1, 3, 7, 8], [0, 1, 3, 6, 8, 9], [0, 1, 3, 5, 8, 9], [0, 1, 2, 3, 5, 8, 9], [0, 1, 2, 4, 7, 8, 9], [0, 1, 2, 4, 5, 7, 9, 10]]:
print(harmony.prime_form(s), harmony.prime_form(s, False))[0, 1, 5, 6, 8] [0, 1, 3, 7, 8]
[0, 2, 3, 6, 7, 9] [0, 1, 3, 6, 8, 9]
[0, 1, 4, 5, 7, 9] [0, 1, 3, 5, 8, 9]
[0, 1, 4, 5, 6, 7, 9] [0, 1, 2, 3, 5, 8, 9]
[0, 1, 2, 5, 6, 7, 9] [0, 1, 2, 4, 7, 8, 9]
[0, 1, 3, 4, 5, 7, 8, 10] [0, 1, 2, 4, 5, 7, 9, 10]The first column is Rahn's and the second Forte's. The sixth case was found by Ian Ring.
Twelve-tone music orders all twelve pitch classes into a row. Schoenberg called his method one "of composing with twelve tones which are related only with one another", and his Suite for Piano, Op. 25, of 1921 to 1923, was the first work with a row in every movement. A row's matrix sets out its forms, the row, its inversion and their retrogrades, in each of twelve transpositions:
r = r + [(row[j] + row[0] - row[i]) % 12]import harmony
row = [0, 11, 7, 4, 2, 9, 3, 8, 10, 1, 5, 6]
print(harmony.all_interval(row))
m = harmony.matrix(row)
print(m[0])
print(m[1])
print([r[0] for r in m])
print(harmony.all_interval([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]))True
[0, 11, 7, 4, 2, 9, 3, 8, 10, 1, 5, 6]
[1, 0, 8, 5, 3, 10, 4, 9, 11, 2, 6, 7]
[0, 1, 5, 8, 10, 3, 9, 4, 2, 11, 7, 6]
FalseThe first line of the matrix is the row, the second the row a semitone higher, and the matrix's first column is the row's inversion. The row is an all-interval row: its eleven successive intervals are all different, as the chromatic scale's are not. Starting on F it reads F, E, C, A, G, D, A flat, D flat, E flat, G flat, B flat, C flat, the first all-interval row known, which Fritz Heinrich Klein called his mother chord in 1921, and which Alban Berg used in his Lyric Suite of 1925 and 1926.
10. Even rhythms
euclid(k, n) spreads k onsets over n steps as evenly as they will go. In 2005 Godfried Toussaint showed that the rhythms it makes include many of the traditional rhythms of the world's music. The algorithm the library uses is Eric Bjorklund's, written for the timing of the high-voltage power supplies of the Spallation Neutron Source accelerator.
import harmony
print(harmony.euclid(3, 8))
print(harmony.euclid(5, 8))
print(harmony.euclid(7, 12))
print(harmony.euclid(5, 16))x..x..x.
x.xx.xx.
x.xx.x.xx.x.
x..x..x..x..x...Three onsets in eight steps is the tresillo, three, three and two, the rhythmic cell under music across Latin America and far beyond it. Five in eight is the Cuban cinquillo, seven in twelve a bell pattern of West African music, and five in sixteen, begun from its third onset, the rhythm of the bossa nova.
11. What the library leaves out
The list of what it does not check is part of understanding the subject.
- Hidden fifths and octaves. Two voices reaching a perfect interval by similar motion, which teachers check between the outer voices when the soprano leaps.
- Doubling. The doubled F sharp of section 6 goes unmarked.
- Resolution. A leading note that does not rise, or a seventh that does not fall.
- Melodic intervals. An augmented second within one voice, or a leap too wide to sing.
- More than four voices, and any texture other than chords on beats.
- Writing. The library marks an exercise, and it does not harmonise a melody. Choosing the chords for a tune is a search over many possibilities, and the rules here are what such a search would test each one against.
For analysing scores rather than exercises, music21, a Python toolkit begun at MIT, has these checks and a great deal more.
Closing
Four-part harmony, at the level of rules, comes down to a few lines you have now read. pitch % 12 puts every note in its pitch class, (pitch - p1) % 12 gives its interval above the bass, fifths_over_1 compares two beats of two voices, and a chord's reading is the set of intervals above its bass. Tuning, set classes and rows are the same arithmetic taken further.
What the rules cannot do is hear. They were taken from music that keeps them, Bach's chorales above all, and that music is broken by composers with reasons of their own: Brahms copied out the fifths of the composers he admired, and Debussy built a cathedral out of them. A mark is exactly what its rule says. Reading the rule is the way to know what that is, and the DKE Library Tutorial is the place to start writing exercises of your own.