Skip to content

Instantly share code, notes, and snippets.

@duhaime
Last active September 28, 2021 14:59
Show Gist options
  • Save duhaime/b8947b22feb0cf2d7ab8c10daeb3bf9f to your computer and use it in GitHub Desktop.
Save duhaime/b8947b22feb0cf2d7ab8c10daeb3bf9f to your computer and use it in GitHub Desktop.
MIDI
import music21
path = 'data/exodus/ambrosia.midi'
score = music21.converter.parse(path, forceSource=True, quantizePost=False)
# validate time signature is 4/4
time_signature = score.parts[0].timeSignature
if time_signature: assert time_signature.ratioString == '4/4'
# validate mode is major / minor
key = score.analyze('key')
assert key.mode == 'minor' or key.mode == 'major'
# transpose to c major / a minor
interval = 60 - key.tonic.midi
if key.mode == 'minor': interval -= 3
score = score.transpose(interval)
# convert midi to string
s = ''
last_offset = 0
for n in score.flat.notes:
if not isinstance(n, music21.chord.Chord):
note = n.pitch.midi
duration = n.duration.type # n.duration.quarterLength
offset = n.offset
delta = offset - last_offset
if delta: s += 'wait_{} '.format(delta)
s += 'note_{}_{} '.format(note, duration)
last_offset = offset
# convert string back to midi
from fractions import Fraction
d = {
'32nd': 1/32,
'16th': 1/16,
'eighth': 1/8,
'quarter': 1/4,
'half': 1/2,
'whole': 1,
}
time = 0
stream = music21.stream.Stream()
for i in s.split():
if i.startswith('note'):
note, duration = i.lstrip('note_').split('_')
n = music21.note.Note(int(note))
n.duration.type = duration
stream.insertIntoNoteOrChord(time, n)
elif i.startswith('wait'):
duration = float(Fraction(i.lstrip('wait_')))
time += duration
else:
print('did not expect', i)
stream.write('midi', fp='yeet.midi')
# play the result
stream.show('midi')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment