In the previous post we looked briefly at intervals, pitches and frequencies, and how to measure them. We also showed that the fundamental frequency differences of 1.5 and 2 are incompatible. So now we explore that a little more, and introduce some standard terminology.

As we know, an octave is divided into 12 semitones, and out of those semitones we can build various sequences of notes, called *scales*. To make our explanations easier, here is a diagram of one octave on a modern keyboard:

A *major scale* consists of playing notes in an octave separated by 2,2,1,2,2,2,1 semitones:

One example is playing all the white notes between two C’s an octave apart.

A *minor scale* has a different sequence of semitones: 2,1,2,2,1,2,2:

A *chromatic scale* consists of all notes: 1,1,1,1,1,1,1,1,1,1,1,1:

A *pentatonic scale* consists of five notes from the octave; such scales are particularly common in folk music; one such scale has the semitone differences 2,2,3,2,3:

Intervals are described in terms of the number of notes between them, counting the first note as one. Thus for the notes of a major scale, we have, starting with the bottom note (known as the *tonic*):

Notes |
Interval |
Semitones |

C – C | Unison | 0 |

C – D | Whole tone | 2 |

C – E | Major third | 4 |

C – F | Perfect fourth | 5 |

C – G | Perfect fifth | 7 |

C – A | Sixth | 9 |

C – B | Seventh | 11 |

C – C’ | Octave | 12 |

We would like a perfect fifth to have a frequency ratio of exactly 1.5, and an octave exactly 2, but these are impossible on a modern keyboard.

Suppose we start with a chromatic scale, and turn it into a cycle of fifths by jumping up seven semitones in sequence. We can obtain this in Python with

[In ]: chr_scale =['C','C#','D','Eb','E','F','F#','G','G#','A','Bb','B'] [In ]: fifths = [chr_scale((i*7)%12) for i in range(13)] [out]: ['C', 'G', 'D', 'A', 'E', 'B', 'F#', 'C#', 'G#', 'Eb', 'Bb', 'F', 'C']

Pythagorean tuning requires that each such jump be a perfect fifth. Since a perfect fifth corresponds to , we can obtain the number of cents needed for a scale by addition, and subtracting 1200 whenever the result is bigger than 1200:

def mod1200(x): return x-(x//1200)*1200

Then:

[In ]: pyth_fifths = [mod1200(i*1200*np.log2(1.5)) for i in range(12)]

Since we can use the same procedure that we used for obtaining the cycle of fifths:

[In ]: pyth_scale = [pyth_fifths[(7*i)%12) for i in range(12)]+[1200] [In ]: [round(x,2) for x in pyth_scale] [Out]: [0.0,113.69,203.91,317.6,407.82,521.51,611.73,701.96,815.64,905.87,1019.55,1109.78,1200]

And we can build a major scale as follows:

[In ]: semis = [0,2,2,1,2,2,2,1] [In ]: pyth_maj = [pyth_scale[i] for i in np.cumsum(semis)] [In ]: [round(x,2) for x in pyth_maj] [Out]: [0.0, 203.91, 407.82, 521.51, 701.96, 905.87, 1109.78, 1200.0]

This is what it sounds like:

The trouble with this tuning is that it’s not perfect for all possible intervals – even fifths. We can investigate all fifths with:

[In ]: for i in range(12): fifth = pyth_scale[(i+7)%12] - pyth_scale[i] print '{0:2} {1:5}'.format(chr_scale[i],round(mod1200(fifth),2)) C 701.96 C# 701.96 D 701.96 Eb 701.96 E 701.96 F 678.49 F# 701.96 G 701.96 G# 701.96 A 701.96 Bb 701.96 B 701.96

The fifth at F is very flat, and will sound pretty awful. We could have realized this even without listing all the fifths first – we had to make a compromise, and that is that including an octave of exactly 1200 cents will be flat with respect to the rest of this tuning. Since at F the fifth is F – C’ (C at the octave) we can expect a flattened fifth from F. Alternately, recall that 12 perfect fifths overshoot 7 octaves by an amount known as the Pythagorean Comma, so that if we are to fit 12 fifths into 7 octaves, at least one of them must be flat. Pythagorean tuning gives us 11 perfect fifths, and one very flat fifth .

Such a poorly mistuned interval is called a *wolf interval*, and minimizing such mistunings while, if possible, keeping as many intervals pure as possible, is the main problem of western tuning.

Since F is a standard modulation from C (one fifth below), a flat fifth at F is highly unsatisfactory. This can be ameliorated by putting C in the middle of the circle of fifths, and tuning in perfect fifths up so say F sharp, and down to G. Then the flat fifth will be F sharp to C sharp. But because of the wolf fifth, Pythagorean tuning forces you not to stray too far away from your original key. This is one of the many problems with Pythagorean tuning.

We can check out the waveform of the wolf fifth, and compare it to a perfect fifth:

[In ]: s = 44100 [In ]: dur = 1 [In ]: dpi = 2.0*np.pi [In ]: hz = 283 [In ]: t = np.linspace(0,dur,dur*s) [In ]: x = np.sin(dpi*hz*t) [In ]: y = np.sin(1.5*dpi*hz*t) [In ]: z = np.sin(2.0**(678.49/1200)*dpi*hz*t) [In ]: pyplot.plot(t,x+y) [In ]: pyplot.plot(t,x+z)

Here is a perfect fifth lasting for a second:

You can see that everything lines up nicely; it would sound sweet and pure.

The wolf fifth looks like this:

We have a shifting pattern of amplitudes; these would appear to the ear as a pulsing sound known as *acoustic beats*. Piano tuners will try to broaden out beats so that they are no longer audible. Audible beats will be heard as a mistuning.

Here is the sound of this wolf fifth: