@@ -20,6 +20,7 @@ def midi_encode(note_seq, resolution=NOTES_PER_BEAT, step=1):
20
20
21
21
play = note_seq [:, :, 0 ]
22
22
replay = note_seq [:, :, 1 ]
23
+ volume = note_seq [:, :, 2 ]
23
24
24
25
# The current pattern being played
25
26
current = np .zeros_like (play [0 ])
@@ -39,7 +40,7 @@ def midi_encode(note_seq, resolution=NOTES_PER_BEAT, step=1):
39
40
# Was off, but now turned on
40
41
evt = midi .NoteOnEvent (
41
42
tick = (tick - last_event_tick ) * step ,
42
- velocity = int (next_volume * MAX_VELOCITY ),
43
+ velocity = int (volume [ tick ][ index [ 0 ]] * MAX_VELOCITY ),
43
44
pitch = index [0 ]
44
45
)
45
46
track .append (evt )
@@ -62,7 +63,7 @@ def midi_encode(note_seq, resolution=NOTES_PER_BEAT, step=1):
62
63
track .append (evt_off )
63
64
evt_on = midi .NoteOnEvent (
64
65
tick = 0 ,
65
- velocity = int (current [ index ] * MAX_VELOCITY ),
66
+ velocity = int (volume [ tick ][ index [ 0 ] ] * MAX_VELOCITY ),
66
67
pitch = index [0 ]
67
68
)
68
69
track .append (evt_on )
@@ -103,88 +104,88 @@ def midi_decode(pattern,
103
104
step = pattern .resolution // NOTES_PER_BEAT
104
105
105
106
# Extract all tracks at highest resolution
106
- merged_notes = None
107
107
merged_replay = None
108
+ merged_volume = None
108
109
109
110
for track in pattern :
110
111
# The downsampled sequences
111
- play_sequence = []
112
112
replay_sequence = []
113
+ volume_sequence = []
113
114
114
115
# Raw sequences
115
- play_buffer = [np .zeros ((classes ,))]
116
116
replay_buffer = [np .zeros ((classes ,))]
117
+ volume_buffer = [np .zeros ((classes ,))]
117
118
118
119
for i , event in enumerate (track ):
119
120
# Duplicate the last note pattern to wait for next event
120
121
for _ in range (event .tick ):
121
- play_buffer .append (np .copy (play_buffer [- 1 ]))
122
122
replay_buffer .append (np .zeros (classes ))
123
+ volume_buffer .append (np .copy (volume_buffer [- 1 ]))
123
124
124
125
# Buffer & downscale sequence
125
- if len (play_buffer ) > step :
126
- # Determine based on majority
127
- notes_sum = np .round (np .sum (play_buffer [:- 1 ], axis = 0 ) / step )
128
- play_sequence .append (play_buffer [0 ])
129
-
130
- # Take the max
126
+ if len (volume_buffer ) > step :
127
+ # Take the min
131
128
replay_any = np .minimum (np .sum (replay_buffer [:- 1 ], axis = 0 ), 1 )
132
129
replay_sequence .append (replay_any )
133
130
131
+ # Determine volume on rounded sum
132
+ volume_sum = np .round (np .sum (volume_buffer [:- 1 ], axis = 0 ) / step )
133
+ volume_sequence .append (volume_sum )
134
+
134
135
# Keep the last one (discard things in the middle)
135
- play_buffer = play_buffer [- 1 :]
136
136
replay_buffer = replay_buffer [- 1 :]
137
+ volume_buffer = volume_buffer [- 1 :]
137
138
138
139
if isinstance (event , midi .EndOfTrackEvent ):
139
140
break
140
141
141
142
# Modify the last note pattern
142
143
if isinstance (event , midi .NoteOnEvent ):
143
144
pitch , velocity = event .data
144
- play_buffer [- 1 ][pitch ] = 1 if velocity > 0 else 0
145
+ volume_buffer [- 1 ][pitch ] = velocity / MAX_VELOCITY
145
146
146
147
# Check for replay_buffer, which is true if the current note was previously played and needs to be replayed
147
- if len (play_buffer ) > 1 and play_buffer [- 2 ][pitch ] > 0 and play_buffer [- 1 ][pitch ] > 0 :
148
+ if len (volume_buffer ) > 1 and volume_buffer [- 2 ][pitch ] > 0 and volume_buffer [- 1 ][pitch ] > 0 :
148
149
replay_buffer [- 1 ][pitch ] = 1
149
150
# Override current volume with previous volume
150
- play_buffer [- 1 ][pitch ] = play_buffer [- 2 ][pitch ]
151
+ volume_buffer [- 1 ][pitch ] = volume_buffer [- 2 ][pitch ]
151
152
152
153
if isinstance (event , midi .NoteOffEvent ):
153
154
pitch , velocity = event .data
154
- play_buffer [- 1 ][pitch ] = 0
155
+ volume_buffer [- 1 ][pitch ] = 0
155
156
156
157
# Add the remaining
157
- play_sequence .append (play_buffer [0 ])
158
158
replay_any = np .minimum (np .sum (replay_buffer , axis = 0 ), 1 )
159
159
replay_sequence .append (replay_any )
160
+ volume_sequence .append (volume_buffer [0 ])
160
161
161
- play_sequence = np .array (play_sequence )
162
162
replay_sequence = np .array (replay_sequence )
163
- assert len (play_sequence ) == len (replay_sequence )
163
+ volume_sequence = np .array (volume_sequence )
164
+ assert len (volume_sequence ) == len (replay_sequence )
164
165
165
- if merged_notes is None :
166
- merged_notes = play_sequence
166
+ if merged_volume is None :
167
167
merged_replay = replay_sequence
168
+ merged_volume = volume_sequence
168
169
else :
169
170
# Merge into a single track, padding with zeros of needed
170
- if len (play_sequence ) > len (merged_notes ):
171
+ if len (volume_sequence ) > len (merged_volume ):
171
172
# Swap variables such that merged_notes is always at least
172
173
# as large as play_sequence
173
- tmp = play_sequence
174
- play_sequence = merged_notes
175
- merged_notes = tmp
176
-
177
174
tmp = replay_sequence
178
175
replay_sequence = merged_replay
179
176
merged_replay = tmp
180
177
181
- assert len (merged_notes ) >= len (play_sequence )
178
+ tmp = volume_sequence
179
+ volume_sequence = merged_volume
180
+ merged_volume = tmp
181
+
182
+ assert len (merged_volume ) >= len (volume_sequence )
182
183
183
- diff = len (merged_notes ) - len (play_sequence )
184
- merged_notes += np .pad (play_sequence , ((0 , diff ), (0 , 0 )), 'constant' )
184
+ diff = len (merged_volume ) - len (volume_sequence )
185
185
merged_replay += np .pad (replay_sequence , ((0 , diff ), (0 , 0 )), 'constant' )
186
+ merged_volume += np .pad (volume_sequence , ((0 , diff ), (0 , 0 )), 'constant' )
186
187
187
- merged = np .stack ([merged_notes , merged_replay ], axis = 2 )
188
+ merged = np .stack ([np . ceil ( merged_volume ) , merged_replay , merged_volume ], axis = 2 )
188
189
# Prevent stacking duplicate notes to exceed one.
189
190
merged = np .minimum (merged , 1 )
190
191
return merged
@@ -203,13 +204,14 @@ def load_midi(fname):
203
204
204
205
assert len (note_seq .shape ) == 3 , note_seq .shape
205
206
assert note_seq .shape [1 ] == MIDI_MAX_NOTES , note_seq .shape
206
- assert note_seq .shape [2 ] == 2 , note_seq .shape
207
+ assert note_seq .shape [2 ] == 3 , note_seq .shape
207
208
assert (note_seq >= 0 ).all ()
208
209
assert (note_seq <= 1 ).all ()
209
210
return note_seq
210
211
211
212
if __name__ == '__main__' :
212
213
# Test
213
- p = midi .read_midifile ("out/test_in.mid" )
214
+ # p = midi.read_midifile("out/test_in.mid")
215
+ p = midi .read_midifile ("data/baroque/bach/0864_01.mid" )
214
216
p = midi_encode (midi_decode (p ))
215
217
midi .write_midifile ("out/test_out.mid" , p )
0 commit comments