-
Notifications
You must be signed in to change notification settings - Fork 14
/
midi2img.py
executable file
·99 lines (74 loc) · 3.16 KB
/
midi2img.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
from music21 import converter, instrument, note, chord
import sys
import numpy as np
from imageio import imwrite
def extractNote(element):
return int(element.pitch.ps)
def extractDuration(element):
return element.duration.quarterLength
def get_notes(notes_to_parse):
""" Get all the notes and chords from the midi files in the ./midi_songs directory """
durations = []
notes = []
start = []
for element in notes_to_parse:
if isinstance(element, note.Note):
if element.isRest:
continue
start.append(element.offset)
notes.append(extractNote(element))
durations.append(extractDuration(element))
elif isinstance(element, chord.Chord):
if element.isRest:
continue
for chord_note in element:
start.append(element.offset)
durations.append(extractDuration(element))
notes.append(extractNote(chord_note))
return {"start":start, "pitch":notes, "dur":durations}
def midi2image(midi_path, max_repetitions = float("inf"), resolution = 0.25, lowerBoundNote = 21, upperBoundNote = 127, maxSongLength = 100):
mid = converter.parse(midi_path)
instruments = instrument.partitionByInstrument(mid)
data = {}
try:
i=0
for instrument_i in instruments.parts:
notes_to_parse = instrument_i.recurse()
notes_data = get_notes(notes_to_parse)
if len(notes_data["start"]) == 0:
continue
if instrument_i.partName is None:
data["instrument_{}".format(i)] = notes_data
i+=1
else:
data[instrument_i.partName] = notes_data
except:
notes_to_parse = mid.flat.notes
data["instrument_0"] = get_notes(notes_to_parse)
for instrument_name, values in data.items():
# https://en.wikipedia.org/wiki/Scientific_pitch_notation#Similar_systems
pitches = values["pitch"]
durs = values["dur"]
starts = values["start"]
index = 0
while index < max_repetitions:
matrix = np.zeros((upperBoundNote-lowerBoundNote,maxSongLength))
for dur, start, pitch in zip(durs, starts, pitches):
dur = int(dur/resolution)
start = int(start/resolution)
if not start > index*(maxSongLength+1) or not dur+start < index*maxSongLength:
for j in range(start,start+dur):
if j - index*maxSongLength >= 0 and j - index*maxSongLength < maxSongLength:
matrix[pitch-lowerBoundNote,j - index*maxSongLength] = 255
if matrix.any(): # If matrix contains no notes (only zeros) don't save it
imwrite(midi_path.split("/")[-1].replace(".mid",f"_{instrument_name}_{index}.png"),matrix.astype(np.uint8))
index += 1
else:
break
if __name__ == "__main__":
midi_path = sys.argv[1]
if len(sys.argv) >= 3:
max_repetitions = int(sys.argv[2])
midi2image(midi_path, max_repetitions)
else:
midi2image(midi_path)