-
Notifications
You must be signed in to change notification settings - Fork 379
/
midi_to_statematrix.py
101 lines (81 loc) · 3.26 KB
/
midi_to_statematrix.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
100
101
import midi, numpy
lowerBound = 24
upperBound = 102
def midiToNoteStateMatrix(midifile):
pattern = midi.read_midifile(midifile)
timeleft = [track[0].tick for track in pattern]
posns = [0 for track in pattern]
statematrix = []
span = upperBound-lowerBound
time = 0
state = [[0,0] for x in range(span)]
statematrix.append(state)
while True:
if time % (pattern.resolution / 4) == (pattern.resolution / 8):
# Crossed a note boundary. Create a new state, defaulting to holding notes
oldstate = state
state = [[oldstate[x][0],0] for x in range(span)]
statematrix.append(state)
for i in range(len(timeleft)):
while timeleft[i] == 0:
track = pattern[i]
pos = posns[i]
evt = track[pos]
if isinstance(evt, midi.NoteEvent):
if (evt.pitch < lowerBound) or (evt.pitch >= upperBound):
pass
# print "Note {} at time {} out of bounds (ignoring)".format(evt.pitch, time)
else:
if isinstance(evt, midi.NoteOffEvent) or evt.velocity == 0:
state[evt.pitch-lowerBound] = [0, 0]
else:
state[evt.pitch-lowerBound] = [1, 1]
elif isinstance(evt, midi.TimeSignatureEvent):
if evt.numerator not in (2, 4):
# We don't want to worry about non-4 time signatures. Bail early!
# print "Found time signature event {}. Bailing!".format(evt)
return statematrix
try:
timeleft[i] = track[pos + 1].tick
posns[i] += 1
except IndexError:
timeleft[i] = None
if timeleft[i] is not None:
timeleft[i] -= 1
if all(t is None for t in timeleft):
break
time += 1
return statematrix
def noteStateMatrixToMidi(statematrix, name="example"):
statematrix = numpy.asarray(statematrix)
pattern = midi.Pattern()
track = midi.Track()
pattern.append(track)
span = upperBound-lowerBound
tickscale = 55
lastcmdtime = 0
prevstate = [[0,0] for x in range(span)]
for time, state in enumerate(statematrix + [prevstate[:]]):
offNotes = []
onNotes = []
for i in range(span):
n = state[i]
p = prevstate[i]
if p[0] == 1:
if n[0] == 0:
offNotes.append(i)
elif n[1] == 1:
offNotes.append(i)
onNotes.append(i)
elif n[0] == 1:
onNotes.append(i)
for note in offNotes:
track.append(midi.NoteOffEvent(tick=(time-lastcmdtime)*tickscale, pitch=note+lowerBound))
lastcmdtime = time
for note in onNotes:
track.append(midi.NoteOnEvent(tick=(time-lastcmdtime)*tickscale, velocity=40, pitch=note+lowerBound))
lastcmdtime = time
prevstate = state
eot = midi.EndOfTrackEvent(tick=1)
track.append(eot)
midi.write_midifile("{}.mid".format(name), pattern)