Last active
December 3, 2022 04:05
-
-
Save mathigatti/7fdafc0f4fbeb5353b567905389ea2b8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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