Skips and Steps

The module introduces the concept of melodic skips and steps. This module uses the music21 library.

Skips and steps refer to the distance, or interval, between two notes in a melody. Most melodies are made up of a combination of steps (short distances or small intervals) and skips (large distances or wide intervals). Many musical traditions exhibit a consistent preference for a higher proportion of steps or skips.

We’ll use an example from a well known religious composition dating from about 1562 by Giovanni Perluigi da Palestrina called the Pope Marcellus Mass. This composition is scored for six voices without instrumental accompaniment. We’ll look at the Kyrie movement in particular, given below:

First we have to access the digital music notation (XML) file. Click here to download the file (original source; encoding credit to Björn Ehnberg). Unzip the *.mxl file and import it using the music21 converter (replace the path given in quotation marks with the file location on your computer):

from music21 import *

kyrie = converter.parse('/Users/username/Downloads/GPPal_MPM_01_Kyrie.mxl')

kyrie.show()

(Check out this module if you’re having trouble viewing the notation.)

We’ll focus on the skips and steps in a single part. Let’s try the part labeled “Tenore I” since that is the first voice to sing:

tenor = kyrie.parts['Tenore I']

tenor.show()

There are a few different ways to get the intervals from a melody (also known as “melodic intervals”). In this module, we’ll use a built-in function in music21 called melodicIntervals() that automatically generates a sequence (technically, a stream) of intervals for a given melody:

intervals = tenor.melodicIntervals()

We can use the len() function to find out how many intervals we have:

len(intervals)
> 193

There are almost 200 intervals in this melody, so let’s just preview the first few. We can use a for loop to iterate over a specific range:

for i in range(0,10):
 print(intervals[i])

> <music21.interval.Interval M2>
> <music21.interval.Interval P1>
> <music21.interval.Interval P1>
> ...

This output tells us the musical interval between each pair of notes, stored as a music21 interval object. The interval object in music21 is really helpful because it supports a number of different musically meaningful ways of representing intervals.

For example, let’s compare a few ways of viewing the first interval:

intervals[0].simpleName
> 'M2'

intervals[0].niceName
> 'Major Second'

intervals[0].directedNiceName
> 'Ascending Major Second'

We’ll explore intervals in more detail in this module. For now, we just want to distinguish between skips and steps. Generally speaking, “steps” are considered one or two half steps (i.e. keys on the piano), and “skips” are anything larger than that.

Because this distinction has a numeric basis, we can sort skips and steps by converting interval names to numbers of semitones:

intervals[0].semitones
> 2

Every interval equal to 1 or 2 should count as a step, and every interval greater than that should count as a skip (we’ll ignore repeated notes [interval = 0] for now). We’ll use conditional if statements.

There’s just one hitch: descending steps are represented as negative numbers. This means that if we have a descending skip of 6 semitones, it will appear as -6, and therefore it won’t be recognized as greater than 2.

The solution is to use the abs() function to find the absolute value for each interval. Then we start counting the number of intervals that meet our criteria. Let’s try it with skips first:

skips = 0

for i in intervals:
 if abs(i.semitones) > 2:
  skips = skips + 1

skips
> 40

It seems that we have 40 skips out of 193 intervals in total.

For steps, we have to define two criteria, since we want to exclude higher values (skips) and lower values (repeated notes). We can use the keyword “and” to combine criteria:

steps = 0

for i in intervals:
 if abs(i.semitones) > 0 and abs(i.semitones) < 3:
  steps = steps + 1

steps
> 128

It seems that there’s a clear preference for steps over skips in the tenor part of this piece of music. Since the tenor part is so similar to the others, we can predict that this preference probably carries through the other voices, but we can certainly check them, too!

Continue this lesson with the next module in sequence.

Extensions

  1. There are 193 intervals in this example, but the sum of skips (40) and steps (128) is only 168. What accounts for this discrepancy?
  2. Can you write a single block of code that counts both skips and steps?
  3. Can you generate a list of intervals without using the melodicIntervals function? (Hint: Try using the zip() function.)