Examples and Demonstrations

The following examples provide a few samples of some of the possibilities available when working with music21.

We start loading music21 like this:

from music21 import *

Creating a Reduction and Labeling Intervals

Let’s load up a score that happens to be in a bunch of parts:

o = corpus.parse('josquin/laDeplorationDeLaMorteDeJohannesOckeghem')
len(o.scores)
 5
o.scores[0].measures(1, 13).show()
../_images/examples_4_0.png

We can merge the scores into a single Score with .mergeScores

mergedScores = o.mergeScores()
scoreExcerpt = mergedScores.measures(127, 133)
scoreExcerpt.show()
../_images/examples_6_0.png
reduction = scoreExcerpt.chordify()

Iterate over the Chords and prepare presentation:

for c in reduction.recurse().getElementsByClass('Chord'):
    c.closedPosition(forceOctave=4, inPlace=True)
    c.annotateIntervals()

Add the reduction and display the results

scoreExcerpt.insert(0, reduction)
scoreExcerpt.show()
../_images/examples_11_0.png

Searching a Large Collection of Works for Ultimate Chord Quality

This example search the entire collection of Bach Chorales stored in the corpus for works that, while in a minor key, end on a minor triad (as opposed to with the more common raised Picardy third).

results = stream.Stream()
results.insert(0, clef.Treble8vbClef())

# Get file paths to all Chorales
for chorale in corpus.chorales.Iterator():
    keyObj = chorale.analyze('key')

    # Select minor-mode chorales only:
    if keyObj.mode != 'minor':
        continue

    # Gather last pitches from all parts into a Chord
    lastChordPitches = []
    for part in chorale.parts:
        lastChordPitches.append(part.flat.pitches[-1])

    cLast = chord.Chord(lastChordPitches)

    # If it's not a minor triad, skip:
    if not cLast.isMinorTriad() and not cLast.isIncompleteMinorTriad():
        continue

    # otherwise, append it to the results with annotations:
    cLast.duration.type = "whole"
    cLast.lyric = chorale.metadata.title

    # put the chord in a measure and put that in the results
    m = stream.Measure()
    m.keySignature = chorale.recurse().getElementsByClass('KeySignature')[0]
    m.append(cLast)

    results.append(m)

# accidentals are probably wrong because of the context.
results.makeAccidentals(inPlace=True)
results.show()
../_images/examples_13_0.png

Searching the Corpus by Locale

This example searches all works in the corpus from two regions in China for the count and percentage of melodic sevenths. These works come from the Essen Folksong database, indexed and stored in the music21 corpus.

# Get an analysis tool
diversityTool = analysis.discrete.MelodicIntervalDiversity()

# get a list to store results.
results = []
# Iterate over two regions
for region in ('shanxi', 'fujian'):
    # Create storage units
    intervalDict = {}
    workCount = 0
    intervalCount = 0
    seventhCount = 0

    # Perform a location search on the corpus and iterate over
    # resulting file name and work number
    for result in corpus.search(region, field='locale'):
        workCount += 1

        # Parse the work and create a dictionary of intervals
        s = result.parse()
        intervalDict = diversityTool.countMelodicIntervals(s, found=intervalDict)

    # Iterate through all intervals, and count totals and sevenths
    for label in intervalDict.keys():
        intervalCount += intervalDict[label][1]
        if label in ['m7', 'M7']:
            seventhCount += intervalDict[label][1]

    # Calculate a percentage and store results
    pcentSevenths = round((seventhCount / float(intervalCount) * 100), 4)
    results.append((region, pcentSevenths, intervalCount, workCount))
# print results
for region, pcentSevenths, intervalCount, workCount in results:
    print('locale: {}: found {} percent melodic sevenths, '
          'out of {} intervals in {} works'.format(
              region, pcentSevenths, intervalCount, workCount))
 locale: shanxi: found 3.1994 percent melodic sevenths, out of 4282 intervals in 77 works
 locale: fujian: found 0.7654 percent melodic sevenths, out of 2613 intervals in 53 works

Pitch and Duration Transformations

This example creates a mensural canon from the Soprano part of a Bach chorale. The procedure extracts the Note objects from the parsed Score object, using the parse() function and the getElementById() method. Then, a new part Stream is created by first scaling the timing and duration of events with the augmentOrDiminish() method and then transposing the pitches with the transpose() method. The modified Stream is then inserted into another Stream and displayed with the show() method.

src = corpus.parse('bach/bwv323.xml')
soprano = src.getElementById('Soprano').recurse().notesAndRests.stream()
soprano.show()
../_images/examples_19_0.png
outputScore = stream.Score()

transformations = [(1.0, 'P1'),
                   (2.0, '-P5'),
                   (0.5, '-P11'),
                   (1.5, -24), # 24 semitones down
                  ]

for speed, transposition in transformations:
    part = soprano.augmentOrDiminish(speed)
    part.transpose(transposition, inPlace=True)
    outputScore.insert(0, part)

outputScore.measures(1, 5).show()
../_images/examples_20_0.png

Basic Counting of and Searching for Musical Elements

Here, we load a file and count the number of G#’s in it. It features the use of the pitches property which gets all Pitch objects from all contained Streams and Stream subclasses recursively:

s = corpus.parse("bach/bwv30.6")
totalGSharps = 0

for p in s.pitches:
    if p.name == 'G#':
        totalGSharps += 1

print(totalGSharps)
 28

Now let’s do something a bit more difficult, we’ll look for all successive four-note segments (excuding repeated notes) within a measure to see the measure expresses melodically a dominant seventh chord.

To do this, we’ll need to know about the .findConsecutiveNotes function. Let’s find a measure with a lot of notes in it to demonstrate:

for m in violin2.getElementsByClass('Measure'):
    if len(m.notes) >= 8:
        break
m.show()
../_images/examples_25_0.png

The findConsecutiveNotes function can find just changes in note name from the previous.

foundNotes = m.findConsecutiveNotes(skipUnisons=True, skipOctaves=True,
                                    skipRests=True, noNone=True)
foundNotes
 [<music21.note.Note C>,
  <music21.note.Note A>,
  <music21.note.Note C>,
  <music21.note.Note A>,
  <music21.note.Note E->]

Okay, I think we have enough information to understand the code now:

display = stream.Stream()

for m in violin2.getElementsByClass('Measure'):
    foundNotes = m.findConsecutiveNotes(skipUnisons=True, skipOctaves=True,
                                        skipRests=True, noNone=True)

    # From this collection of Notes we gather all Pitches
    foundPitches = stream.Stream(foundNotes).pitches

    # skip ahead if there aren't the right number of pitches for a dominant seventh
    if len(foundPitches) != 4:
        continue


    # make it into a chord.
    c = chord.Chord(foundPitches)

    if c.isDominantSeventh() is False:
        continue

    # now lets label the chord:
    c.lyric = "m. {}".format(m.number)
    c.duration.type = 'whole'


    cClosed = c.closedPosition()
    measureForChord = stream.Measure()
    measureForChord.append(cClosed)

    display.append(measureForChord)
    display.append(m)

Okay, let’s see what we found!

display.show()
../_images/examples_31_0.png