Pedal Point

This module illustrates how to identify and analyze a pedal point.

A pedal point is a tone that is sustained (or repeated) through several different chords or harmonies. It is often, but not always, in the lowest voice. Typically, it will function as a chord tone in some of these harmonies, and a non-chord tone in at least one. To identify a pedal point, you must analyze the harmonic context.

We’ll start by looking at a simplified excerpt from one of the composer J. S. Bach’s most famous keyboard preludes:

from music21 import *

prelude = converter.parse('tinyNotation: 4/4 GG16 D G B f G B f GG D G B f G B f GG E- A c f# A c f# GG E- A c f# A c f# GG E G c g G c g GG E G c g G c g')

Instead of loading the whole prelude, I’m just creating a simplified version of a short passage using music21’s tinyNotation. (To learn more about tinyNotation, click here.)

In this example, each bar outlines the notes of a different chord: G7, f#o, and C major. Or in the key of C major: V7, viio, I6/4. However, we note that despite the changing harmonies, the low G (on the bottom line of the staff) is regularly repeated.

This is a classic pedal point (in the original score, this note is sustained as well.) The note G has a role to play in two of the three chords: it is the root of the G7 chord and the fifth of the C major chord. It is a non-chord tone in the F# diminished chord.

The principle of the pedal point is that through repetition (or being sustained over a long period of time), the pedal note generates inertia, and our ears are able to hear the harmony changing “over” it, even if it doesn’t quite fit into every chord. This, in turn, makes it even more exciting when the pedal note finally changes. The pedal point is often built on the dominant (the fifth scale degree) to build tension before a return to the tonic.

Let’s take a look at a musical example in context. This is a choral work by the composer Amy Beach called “Prayer of a Tired Child” from the music21 corpus:

beach = corpus.parse('beach/prayer_of_a_tired_child.musicxml')

First, follow the score as you listen. We’ll focus on the vocal parts, rather than the piano accompaniment. The first phrase extends from measure 1 to measure 5. We notice that during this entire phrase, the lowest voice (Alto II) remains on the same pitch throughout (B-flat below middle C). In fact, the highest voice (Soprano I) also sustains a B-flat an octave higher until measure 4. In other words, we have a pedal point in the outer voices against changing harmonies in the inner voices.

Starting from the first quarter note in the vocal part, we have the following harmonies: E-flat, G, B-flat; B-flat, F, A-flat; E-flat, G, B-flat; and B-flat, D, F. In the key of E-flat major, we can understand this movement as alternating between I and V, even if we’re missing a note here and there.

The eighth-note pickups to bar three frame the B-flats as non-chord tones for the first time, as we have B-flat against C and E-flat in the Soprano II and Alto I parts. As discussed above, however, this is pretty typical.

Let’s use the music21 toolkit to analyze a little deeper. First, let’s isolate the vocal parts by removing the piano part. There are a number of ways to do this, but here we’ll use the .remove function and a while loop:

while len( > 4:

This block of code removes parts, starting from the bottom, until the total number of parts is equal to four. Just as with lists, we use the index “-1” to specify the bottom (last) part. (We could also use “4,” but “-1” is more generalizable.) If we view the score again, the piano part is gone:

Next, in order to analyze the chords, we want to use the chordify function. This allows us to reduce all of the parts onto a single staff:

beach_chords = beach.chordify()

We can view the chords on their own or, to make things a bit clearer, add the chords to a single staff below the vocal parts, like a piano reduction:

beach.insert(0, beach_chords)

The insert function allows us to add an element (beach_chords) to an existing score (technically, a stream) at a specified offset from the beginning (0, since we want the parts to line up). Now when we view the original score, a fifth staff has been added at the bottom with the reduction.

Now let’s analyze and label the the chords. First, we have to establish the key by creating a music21 key object:

beach_key = key.Key('E-')

Next, we’ll iterate over each chord in the last part of the score (the reduction) using a for loop along with .recurse() (to search through multiple depths of the stream) and .getElementsByClass to specify chords. For each chord (“c”), we generate a Roman numeral in our specified key, and then add the Roman numeral label below the note (as though it were a lyric).

Additionally, since we modulate to C minor in the middle of the piece, we only want to use the E-flat major Roman numerals where applicable. Therefore, let’s just analyze the first six bars:

for c in[-1].measures(1,6).recurse().getElementsByClass('Chord'):
 rn = roman.romanNumeralFromChord(c, beach_key)

We’ll use a similar block of code to add labels in C minor from measures 7-19:

beach_minor = key.Key('c')

for c in[-1].measures(7,19).recurse().getElementsByClass('Chord'):
 rn = roman.romanNumeralFromChord(c, beach_minor)

And then the return to E-flat major in bars 20-31 (remember to switch back the key in the second line of the code):

for c in[-1].measures(20,31).recurse().getElementsByClass('Chord'):
 rn = roman.romanNumeralFromChord(c, beach_key)

Now we have a fully analyzed score, which will allow us to more easily examine the harmonic role of the pedal point throughout the piece. For example, notice how the pedal note remains on the fifth scale degree by switching from B-flat to G when the piece modulates to C minor in the middle section.

Now let’s try adding another layer of labels corresponding to the role the pedal point plays in the harmony. This block of code will determine whether the pedal note B-flat is the root in measures 1-6 using an if statement:

for c in[-1].measures(1,6).recurse().getElementsByClass('Chord'):
 if pitch.Pitch('B-').name == c.root().name:

(Note that we must include the .name property so that matches in different octaves will be recognized.)

It turns out that B-flat is the root note for just about every other chord. And now for the middle section:

for c in[-1].measures(7,19).recurse().getElementsByClass('Chord'):
 if pitch.Pitch('G').name == c.root().name:

Again, the pedal note is quite frequently the root note, meaning that we have a lot of dominant harmonies. See the extensions below for ideas on how to conduct an even more in-depth analysis.


  1. Try using .third, .fifth, and .seventh to determine how often the pedal tones take on other roles in the chords in this piece. Or you can use .getChordStep() for even more flexibility.
  2. Can you write a loop or function that labels the entire piece and automatically takes the modulation in the middle section into account?

Further Reading

For more on pedal points, check out this page.