OLD | NEW |
1 # This file is part of LilyPond, the GNU music typesetter. | 1 # This file is part of LilyPond, the GNU music typesetter. |
2 # | 2 # |
3 # Copyright (C) 2001--2020 Han-Wen Nienhuys <hanwen@xs4all.nl> | 3 # Copyright (C) 2001--2020 Han-Wen Nienhuys <hanwen@xs4all.nl> |
4 # Jan Nieuwenhuizen <janneke@gnu.org> | 4 # Jan Nieuwenhuizen <janneke@gnu.org> |
5 # | 5 # |
6 # | 6 # |
7 # LilyPond is free software: you can redistribute it and/or modify | 7 # LilyPond is free software: you can redistribute it and/or modify |
8 # it under the terms of the GNU General Public License as published by | 8 # it under the terms of the GNU General Public License as published by |
9 # the Free Software Foundation, either version 3 of the License, or | 9 # the Free Software Foundation, either version 3 of the License, or |
10 # (at your option) any later version. | 10 # (at your option) any later version. |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
103 raise error('the first midi command in the track is a repeat') | 103 raise error('the first midi command in the track is a repeat') |
104 | 104 |
105 def _read_two_bytes (status, nextbyte, getbyte): | 105 def _read_two_bytes (status, nextbyte, getbyte): |
106 return status, nextbyte | 106 return status, nextbyte |
107 | 107 |
108 def _read_three_bytes (status, nextbyte, getbyte): | 108 def _read_three_bytes (status, nextbyte, getbyte): |
109 return status, nextbyte, getbyte() | 109 return status, nextbyte, getbyte() |
110 | 110 |
111 def _read_string (nextbyte, getbyte): | 111 def _read_string (nextbyte, getbyte): |
112 length = _get_variable_length_number (nextbyte, getbyte) | 112 length = _get_variable_length_number (nextbyte, getbyte) |
113 return ''.join(chr(getbyte()) for i in xrange(length)) | 113 return ''.join(chr(getbyte()) for i in range(length)) |
114 | 114 |
115 def _read_f0_byte (status, nextbyte, getbyte): | 115 def _read_f0_byte (status, nextbyte, getbyte): |
116 if status == 0xff: | 116 if status == 0xff: |
117 return status, nextbyte, _read_string(getbyte(), getbyte) | 117 return status, nextbyte, _read_string(getbyte(), getbyte) |
118 return status, _read_string(nextbyte, getbyte) | 118 return status, _read_string(nextbyte, getbyte) |
119 | 119 |
120 _read_midi_event = ( | 120 _read_midi_event = ( |
121 _first_command_is_repeat, # 0 | 121 _first_command_is_repeat, # 0 |
122 None, # 10 | 122 None, # 10 |
123 None, # 20 | 123 None, # 20 |
124 None, # 30 | 124 None, # 30 |
125 None, # 40 | 125 None, # 40 |
126 None, # 50 | 126 None, # 50 |
127 None, # 60 data entry??? | 127 None, # 60 data entry??? |
128 None, # 70 all notes off??? | 128 None, # 70 all notes off??? |
129 _read_three_bytes, # 80 note off | 129 _read_three_bytes, # 80 note off |
130 _read_three_bytes, # 90 note on | 130 _read_three_bytes, # 90 note on |
131 _read_three_bytes, # a0 poly aftertouch | 131 _read_three_bytes, # a0 poly aftertouch |
132 _read_three_bytes, # b0 control | 132 _read_three_bytes, # b0 control |
133 _read_two_bytes, # c0 prog change | 133 _read_two_bytes, # c0 prog change |
134 _read_two_bytes, # d0 ch aftertouch | 134 _read_two_bytes, # d0 ch aftertouch |
135 _read_three_bytes, # e0 pitchwheel range | 135 _read_three_bytes, # e0 pitchwheel range |
136 _read_f0_byte, # f0 | 136 _read_f0_byte, # f0 |
137 ) | 137 ) |
138 | 138 |
139 def _parse_track_body (data, clocks_max): | 139 def _parse_track_body (data, clocks_max): |
140 # This seems to be the fastest way of getting bytes in order as integers. | 140 # This seems to be the fastest way of getting bytes in order as integers. |
141 dataiter = iter(array.array('B', data)) | 141 dataiter = iter(array.array('B', data)) |
142 getbyte = dataiter.next | 142 getbyte = dataiter.__next__ |
143 | 143 |
144 time = 0 | 144 time = 0 |
145 status = 0 | 145 status = 0 |
146 try: | 146 try: |
147 for nextbyte in dataiter: | 147 for nextbyte in dataiter: |
148 time += _get_variable_length_number (nextbyte, getbyte) | 148 time += _get_variable_length_number (nextbyte, getbyte) |
149 if clocks_max and time > clocks_max: | 149 if clocks_max and time > clocks_max: |
150 break | 150 break |
151 nextbyte = getbyte() | 151 nextbyte = getbyte() |
152 if nextbyte >= 0x80: | 152 if nextbyte >= 0x80: |
153 status = nextbyte | 153 status = nextbyte |
154 nextbyte = getbyte() | 154 nextbyte = getbyte() |
155 yield time, _read_midi_event[status >> 4] (status, nextbyte, getbyte
) | 155 yield time, _read_midi_event[status >> 4] (status, nextbyte, getbyte
) |
156 except StopIteration: | 156 except StopIteration: |
157 # If the track ended just before the start of an event, the for loop | 157 # If the track ended just before the start of an event, the for loop |
158 # will exit normally. If it ends anywhere else, we end up here. | 158 # will exit normally. If it ends anywhere else, we end up here. |
159 print len(list(dataiter)) | 159 print(len(list(dataiter))) |
160 raise error('a track ended in the middle of a MIDI command') | 160 raise error('a track ended in the middle of a MIDI command') |
161 | 161 |
162 def _parse_hunk (data, pos, type, magic): | 162 def _parse_hunk (data, pos, type, magic): |
163 if data[pos:pos+4] != magic: | 163 if data[pos:pos+4] != magic: |
164 raise error ('expected %r, got %r' % (magic, data[pos:pos+4])) | 164 raise error ('expected %r, got %r' % (magic, data[pos:pos+4])) |
165 try: | 165 try: |
166 length, = struct.unpack ('>I', data[pos+4:pos+8]) | 166 length, = struct.unpack ('>I', data[pos+4:pos+8]) |
167 except struct.error: | 167 except struct.error: |
168 raise error ('the %s header is truncated (may be an incomplete download)
' % type) | 168 raise error ('the %s header is truncated (may be an incomplete download)
' % type) |
169 endpos = pos + 8 + length | 169 endpos = pos + 8 + length |
170 data = data[pos+8:endpos] | 170 data = data[pos+8:endpos] |
171 if len(data) != length: | 171 if len(data) != length: |
172 raise error('the %s is truncated (may be an incomplete download)' % type
) | 172 raise error('the %s is truncated (may be an incomplete download)' % type
) |
173 return data, endpos | 173 return data, endpos |
174 | 174 |
175 def _parse_tracks (midi, pos, num_tracks, clocks_max): | 175 def _parse_tracks (midi, pos, num_tracks, clocks_max): |
176 if num_tracks > 256: | 176 if num_tracks > 256: |
177 raise error('too many tracks: %d' % num_tracks) | 177 raise error('too many tracks: %d' % num_tracks) |
178 for i in xrange(num_tracks): | 178 for i in range(num_tracks): |
179 trackdata, pos = _parse_hunk (midi, pos, 'track', 'MTrk') | 179 trackdata, pos = _parse_hunk (midi, pos, 'track', 'MTrk') |
180 yield list (_parse_track_body (trackdata, clocks_max)) | 180 yield list (_parse_track_body (trackdata, clocks_max)) |
181 # if pos < len(midi): | 181 # if pos < len(midi): |
182 # warn | 182 # warn |
183 | 183 |
184 def parse_track (track, clocks_max=None): | 184 def parse_track (track, clocks_max=None): |
185 track_body, end = _parse_hunk (track, 0, 'track', 'MTrk') | 185 track_body, end = _parse_hunk (track, 0, 'track', 'MTrk') |
186 # if end < len(track): | 186 # if end < len(track): |
187 # warn | 187 # warn |
188 return list (_parse_track_body (track_body, clocks_max)) | 188 return list (_parse_track_body (track_body, clocks_max)) |
189 | 189 |
190 def parse (midi, clocks_max=None): | 190 def parse (midi, clocks_max=None): |
191 header, first_track_pos = _parse_hunk(midi, 0, 'file', 'MThd') | 191 header, first_track_pos = _parse_hunk(midi, 0, 'file', 'MThd') |
192 try: | 192 try: |
193 format, num_tracks, division = struct.unpack ('>3H', header[:6]) | 193 format, num_tracks, division = struct.unpack ('>3H', header[:6]) |
194 except struct.error: | 194 except struct.error: |
195 raise error('the file header is too short') | 195 raise error('the file header is too short') |
196 # if division < 0: | 196 # if division < 0: |
197 # raise error ('cannot handle non-metrical time') | 197 # raise error ('cannot handle non-metrical time') |
198 tracks = list (_parse_tracks (midi, first_track_pos, num_tracks, clocks_max)
) | 198 tracks = list (_parse_tracks (midi, first_track_pos, num_tracks, clocks_max)
) |
199 return (format, division*4), tracks | 199 return (format, division*4), tracks |
OLD | NEW |