Skip to content

Instantly share code, notes, and snippets.

@mathigatti
Last active December 3, 2022 04:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save mathigatti/7fdafc0f4fbeb5353b567905389ea2b8 to your computer and use it in GitHub Desktop.
Save mathigatti/7fdafc0f4fbeb5353b567905389ea2b8 to your computer and use it in GitHub Desktop.
import numpy
from music21 import instrument, note, stream, chord
import sys
import numpy as np
def convert_to_float(frac_str):
try:
return float(frac_str)
except ValueError:
num, denom = frac_str.split('/')
try:
leading, num = num.split(' ')
whole = float(leading)
except ValueError:
whole = 0
frac = float(num) / float(denom)
return whole - frac if whole < 0 else whole + frac
def note_number_to_name(note_number):
#print(note_number)
semis = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']
# Ensure the note is an int
note_number = int(np.round(note_number))
# Get the semitone and the octave, and concatenate to create the name
output = semis[note_number % 12] + str(note_number//12 - 1)
#print(output)
return output
def duration(note_text):
if "|" in note_text:
return convert_to_float(note_text.split("|")[-1])
# It's invalid but's let's return 0.5 to make it more resilient
else:
return 0.5
def create_midi(notes_sequence,output_file="output.mid"):
offset = 0
output_notes = []
prev_note = 60
# create note and chord objects based on the values generated by the model
for token in notes_sequence:
# starting token
if token == "S":
continue
token_duration = duration(token)
token = token.split("|")[0]
# token is a chord
if '.' in token:
notes_in_chord = token.split('.')
notes = []
for current_note in notes_in_chord:
new_note = note.Note(note_number_to_name(prev_note+int(current_note)))
new_note.storedInstrument = instrument.Piano()
notes.append(new_note)
prev_note = int(notes_in_chord[0]) + prev_note
new_chord = chord.Chord(notes,quarterLength=token_duration)
new_chord.offset = offset
output_notes.append(new_chord)
# token is a rest
elif "R" in token:
output_notes.append(note.Rest(quarterLength=token_duration))
# token is a single note
else:
new_note = note.Note(note_number_to_name(prev_note+int(token)),quarterLength=token_duration)
prev_note = int(token) + prev_note
new_note.offset = offset
new_note.storedInstrument = instrument.Piano()
output_notes.append(new_note)
# increase offset each iteration so that notes do not stack
offset += token_duration
midi_stream = stream.Stream(output_notes)
midi_stream.write('midi', fp=output_file)
if __name__ == '__main__':
notes_sequence = sys.argv[1].split()[2:]
if len(sys.argv) > 2:
output_path = sys.argv[2]
create_midi(notes_sequence,output_path)
else:
create_midi(notes_sequence)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment