User’s Guide, Chapter 43: Searching in and Among Scores

(This Chapter is a work in progress)

from music21 import *
lamb1 = corpus.parse('palestrina/agnus_I_01')
lamb1.measures(0, 7).show()
../_images/usersGuide_43_searching1_3_0.png

Nice Stretto going from the beginning! Okay, let’s search for some things…

Let’s find all instances of three whole notes in a row…

justTheNotes = lamb1.recurse().notes
searchList = [note.Note(type='whole'), note.Note(type='whole'), note.Note(type='whole')]

search.rhythmicSearch(justTheNotes,
                      searchList)
 [0, 107, 108, 189, 216, 217, 243, 251, 302, 303, 324]
secondEntry = justTheNotes[107]
secondEntry
 <music21.note.Note C>
secondEntry.getContextByClass('Part')
 <music21.stream.Part spine_2>
secondEntry.measureNumber
 1
secondEntry.beat
 1.0
lamb2 = lamb1.stripTies()
justTheNotes = lamb2.recurse().notes
search.rhythmicSearch(justTheNotes,
                      searchList)
 [0, 102, 207, 208, 232, 240, 241, 287, 288, 298]
thirdEntry = justTheNotes[207]
p = thirdEntry.getContextByClass('Part')
p.recurse().getElementsByClass('Instrument')[0]
 <music21.instrument.Tenor 'Tenor'>
entryPoints = search.rhythmicSearch(justTheNotes, searchList)
for notePosition in entryPoints:
    startingNote = justTheNotes[notePosition]
    startingMeasure = startingNote.measureNumber
    startingBeat = startingNote.beat
    startingPart = startingNote.getContextByClass('Part')
    startingInstrument = startingPart.recurse().getElementsByClass('Instrument')[0]
    print(startingNote, startingMeasure, startingBeat, startingInstrument)
 <music21.note.Note F> 4 3.0 Soprano
 <music21.note.Note C> 1 1.0 Alto
 <music21.note.Note B-> 5 1.0 Tenor
 <music21.note.Note B-> 5 3.0 Tenor
 <music21.note.Note G> 12 3.0 Tenor
 <music21.note.Note B-> 18 1.0 Tenor
 <music21.note.Note C> 18 3.0 Tenor
 <music21.note.Note F> 1 3.0 Bass
 <music21.note.Note F> 2 1.0 Bass
 <music21.note.Note G> 5 3.0 Bass
searchStream2 = stream.Stream([key.KeySignature(-1),
                               note.Note('C', type='whole'),
                               note.Note('C', type='whole'),
                               note.Note('D', type='whole')])
justTheNotes = lamb2.recurse().notes

transposeInterval = interval.GenericInterval(2)

for unused in range(12): # unison to seventh
    searchStream2.transpose(transposeInterval, inPlace=True)
    # here is the compact way of doing the same thing:
    # useSearchList = [n.transpose(transposeInterval) for n in searchList2]
    entryPoints = search.noteNameRhythmicSearch(justTheNotes, searchStream2.notes)
    print('Searching for ' + str(searchStream2.notes[0]))
    for notePosition in entryPoints:
        startingNote = justTheNotes[notePosition]
        startingMeasure = startingNote.measureNumber
        startingBeat = startingNote.beat
        startingPart = startingNote.getContextByClass('Part')
        startingInstrument = startingPart.recurse().getElementsByClass('Instrument')[0]
        print(startingNote, startingMeasure, startingBeat, startingInstrument)
 Searching for <music21.note.Note D>
 Searching for <music21.note.Note E>
 Searching for <music21.note.Note F>
 <music21.note.Note F> 4 3.0 Soprano
 <music21.note.Note F> 1 3.0 Bass
 Searching for <music21.note.Note G>
 Searching for <music21.note.Note A>
 Searching for <music21.note.Note B->
 <music21.note.Note B-> 5 1.0 Tenor
 Searching for <music21.note.Note C>
 <music21.note.Note C> 1 1.0 Alto
 Searching for <music21.note.Note D>
 Searching for <music21.note.Note E>
 Searching for <music21.note.Note F>
 <music21.note.Note F> 4 3.0 Soprano
 <music21.note.Note F> 1 3.0 Bass
 Searching for <music21.note.Note G>
 Searching for <music21.note.Note A>

Advanced Topics: Writing your own algorithm

Let’s say that you want to compare notes by pitchClass and not by name, we don’t have an algorithm for that, but it’s pretty easy to write your own and use search.streamSearchBase to implement it.

The algorithm should check to see if two notes have the same pitchClass and return True if they do:

def pitchClassEqual(n1, n2):
    if n1.pitch.pitchClass == n2.pitch.pitchClass:
        return True
    else:
        return False

Now we can run a search on something with this algorithm:

s = converter.parse('tinyNotation: 5/4 b4 c d# e f b# e- f-').recurse().notes
searchList = [note.Note('C'), note.Note('E-'), note.Note('E')]

search.streamSearchBase(s, searchList, algorithm=pitchClassEqual)
 [1, 5]

But if you really want to search on pitch classes, see search.serial