07.01.07

The Tetrachords and “Familiarity”

Posted in music theory, python at 9:51 am by bmccosar

I’ve developed an interest in the pitch class sets of cardinality 4, the tetrachords. The other day, as I was experimenting with these sets in my practice sessions, I noticed something: some of the pc sets felt more “familiar” than others.

This makes sense; tetrachords are the basis of jazz harmony. For example, the C major 7th chord “C E G B”, as a pitch class set, is [0, 1, 5, 8] in prime form. (This can also be written 0158 in compressed notation.) When you are used to playing jazz, hearing the pitch class set 0158 makes you think “major seventh.” Even if the set is inverted, in this case it retains the same sound — 0158 happens to have an inversion axis, that is, a number n so that the operation T(n)I returns the same group of pitch classes. In this case, for 0158, n = 1.

On the other hand, some of the tetrachords sound very unfamiliar. A good example would be 0347. If I tried to make sense of this as a jazz chord, I’d have to translate to notes: C Eb E G. Now, this could have a number of names, depending on the inversion: “C major add flat 3″, “E minor major 7th flat 6″, “Eb major sixth flat 9″, and even some crazy combination of G sus 4, G6, and G+. Just as the standard terminology fails at precisely identifying this chord, so the ear finds it unfamiliar.

My intuition was that there was a mathematical reason for this, and I was right. It has to do with subsets.

If you take a familiar scale, for instance the C major scale, you can find the equivalent prime form pitch class set: 013568A. If I take any tetrachord from the C major scale, for instance 6A15, I can reduce it to prime form: the familiar 0158. This makes sense; we know that the major scale contains major seventh chords. What is different here is that I can say that 0158 is a prime subset of 013568A — there exists some operation Tn or TnI which will make 0158 a literal subset. (In this case, the operation T(5) gives 56A1 — and [5,6,A,1] is a literal subset of [0,1,3,5,6,8,A].)

That’s how I came to write a short Python program to provide clues about familiarity. Here’s the basic algorithm:

  1. Take any one of the 29 prime tetrachords. [See this article for the reason there are only 29.]
  2. Take any of the following familiar scales: major, jazz minor, harmonic minor, pentatonic, diminished, augmented, and whole tone.
  3. Find out if the given tetrachord is a prime subset of the given scale. If it is, make note of it.
  4. Repeat the above until all the possibilities are exhausted.

It was instruction #4, above, that made me turn this over to Python.

In case you’re not interested in the programming end, though, here’s a table of the results. I’ve listed each of the 29 possible tetrachord pitch class sets in the first column. The second column, inv, is the number of inversion axes for the given pitch class. The last columns are only filled in if they match the scales above.

One note: I sorted these by the number of inversion axes. Some, you will notice, have none — this means that if you perform a pitch class inversion on the set, you get a new pattern.

Case in point: the prime form for dominant 7th chords is exactly the same as for half-diminished (minor 7th flat 5) chords — 0258. On the table, 0258 has no inversion axis; therefore, one pattern corresponds to the notes in the half diminished (0258) and its inverse to the dominant 7th (0368, if you invert, normalize, and transpose so the first note is zero).

On the other hand, the more inversion axes a set has, the more symmetrical it will be — and, for the improviser, harder to generate unique melodies.

pc set inv






0124 0 . . . . . . .
0125 0 . . . . . . .
0126 0 . . . . . . .
0135 0 major jazz harm . . . .
0136 0 major jazz harm . dim . .
0137 0 major jazz harm . dim . .
0146 0 . jazz harm . dim . .
0147 0 . . harm . dim . .
0148 0 . jazz harm . . aug .
0157 0 major jazz harm . . . .
0236 0 . jazz harm . dim . .
0237 0 major jazz harm . . . .
0247 0 major jazz harm penta . . .
0258 0 major jazz harm . dim . .
0123 1 . . . . . . .
0127 1 . . . . . . .
0134 1 . jazz harm . dim . .
0145 1 . . harm . . aug .
0156 1 major . harm . . . .
0158 1 major . harm . . aug .
0235 1 major jazz harm . dim . .
0246 1 major jazz . . . . wtone
0248 1 . jazz harm . . . wtone
0257 1 major jazz harm penta . . .
0347 1 . . harm . dim aug .
0358 1 major jazz harm penta dim . .
0167 2 . . . . dim . .
0268 2 . jazz . . dim . wtone
0369 4 . . harm . dim . .

If you want the details of how I generated this table, the program is simple, and is given below.

familiarity.py — This program requires some modules I wrote earlier: pcset.py, pcops.py, and easypc.py

#!/usr/bin/env python

from pcops import *
from easypc import EasyPcSet as Pcs

tetrachords = """
0123 0124 0125 0126 0127
0134 0135 0136 0137 0145
0146 0147 0148 0156 0157
0158 0167 0235 0236 0237
0246 0247 0248 0257 0258
0268 0347 0358 0369
"""

rawscales = """
013568A,major
013468A,jazz
0134689,harm
02479,penta
0134679A,dim
014589,aug
02468A,wtone
"""

def tetras():
    for e in tetrachords.split():
        yield Pcs(e)

def scales():
    for line in rawscales.split():
        s, name = line.split(',')
        yield Pcs(s), name

for t in tetras():
    print t, "\t", len(t.com()), "\t",
    for s, name in scales():
        if is_prime_subset(s,t):
            print name, "\t",
        else:
            print ".", "\t",
    print

Software examples on this page are licensed under the CC-GNU GPL.

Leave a Comment