See Edit below for a work-in-progress MRE
I'm trying to transform the text
output of music21 to include octave numbers and correct enharmonic spelling.
As background, I'm a javascript programmer, new to music21 and python.
The following
myMusic = converter.parse("midi")
myMusic.show("text")
yields
Time Actual output Desired Output
{0.0} <music21.note.Note C> C4
{0.1} <music21.note.Note D#> E-4
{0.2} <music21.note.Note G> G4
{0.3} <music21.note.Note G> G4
Where there are two issues:
How do I include the octave in the text output? (Interestingly, when there are chords, the octave of each note does appear.
The D#
should be an Eb
, i.e., should be interpreted in a tonal context. I'd like to run EnharmonicSimplifier.bestPitches()
on the whole parsed midi file to correct this, but from the docs, it appears that it can only be run on a note list
.
Am I going about this wrong? Should I be outputting to a different format to get this info? I need timepoints (offset is ok), octave numbers, and correctly-spelled pitches. Maybe I'm missing intermediate processing?
Any guidance appreciated.
EDIT: Work in progress MRE, solves issue 1. (badly?), but not 2.
from music21 import *
environment.set('autoDownload', 'allow')
stream1 = converter.parse("https://upload.wikimedia.org/wikipedia/commons/5/55/MIDI_sample.mid")
for n in stream1.recurse().notes:
try:
print(n.offset, n.nameWithOctave)
except Exception as e:
print(n.offset, *n.pitches)
Yields (excerpted)
237.5 C2
238.0 F#2
238.2 F#2
238.5 C2 F#2
238.7 B-2
1
.show()
is nice at a glance when debugging but not ideal for structured output. Have a look at recurse()
. music21 has a container ontology: objects are "in" voices, "in" measures, "in" parts, "in" scores. So if you start top-down from a score and want to walk every nested container, just use recurse():
for n in myStream.recurse().notes:
print(n.offset, ' '.join(p.nameWithOctave for p in n.pitches))
Note properties: http://web.mit.edu/music21/doc/moduleReference/moduleNote.html
2
simplifyMultipleEnharmonics()
takes an iterable of pitches (or things that can be converted to pitches, but faster to give it the pitches if you've got 'em). Every Note or Chord object has a pitches
attribute, so you can safely call .pitches
on Notes or Chords while looping through your parsed file and send that tuple of pitches to simplifyMultipleEnharmonics
, along with your Key object.
for n in myStream.recurse().notes:
closest_key = n.getContextByClass(key.Key)
n.pitches = pitch.simplifyMultipleEnharmonics(n.pitches, keyContext=closest_key)