-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathMidiEventDecoder.py
77 lines (70 loc) · 3.1 KB
/
MidiEventDecoder.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
from MidiParser import MidiParser
from MidiEvents import *
from Util import Util
# decodes data from the MidiParser into data easier to work with in MidiData
# (will decode each piece of data from midi_parser into an event,
# including header chunk pieces)
class MidiEventDecoder:
def __init__(self, midi_filename):
self.midi_parser = MidiParser(midi_filename)
self.running_status = False
self.last_channel_status_byte = None # the first byte of the last channel event that didn't use running status
return
def has_more_events(self):
return self.midi_parser.has_more_data()
# be sure to call this once before calling next_event
def header_data(self):
data = HeaderData()
data.set_from_bytes(self.midi_parser.read_next_data(),
self.midi_parser.read_next_data())
return data
# returns a MidiEvent
def next_event(self):
return self.midi_event(self.midi_parser.read_next_data())
# creates a MidiEvent from the midi_data
def midi_event(self, midi_data):
# check if TrackHeader
if midi_data[0:4] == b'MTrk':
track_header = TrackHeader()
track_header.set_from_bytes(midi_data)
return track_header
# find delta_time
temp_data = midi_data
delta_time_bytes_length = 0
while Util.msb_is_one(temp_data[delta_time_bytes_length:]):
delta_time_bytes_length += 1
delta_time_bytes_length += 1
delta_time = temp_data[:delta_time_bytes_length]
midi_data = temp_data[delta_time_bytes_length:]
# Meta Event
if midi_data[0:1] == b'\xff':
if midi_data[1] in EventDictionaries.META_EVENT_DICTIONARY:
meta_event_class = EventDictionaries.META_EVENT_DICTIONARY[midi_data[1]]
else:
meta_event_class = MetaEvent
meta_event = meta_event_class()
meta_event.set_delta_time_from_bytes(delta_time)
meta_event.set_from_bytes(midi_data)
return meta_event
# System Event
if midi_data[0:1] == b'\xf0' or midi_data[0:1] == b'\xf7':
system_event = SystemExclusiveEvent()
system_event.set_delta_time_from_bytes(delta_time)
system_event.set_from_bytes(midi_data)
return system_event
# Channel Event
if Util.msb_is_one(midi_data): # running status
self.last_channel_status_byte = midi_data[0:1]
else: # not running status
midi_data = self.last_channel_status_byte + midi_data
channel_event_identifier = midi_data[0] & int('f0', 16)
if channel_event_identifier in EventDictionaries.CHANNEL_EVENT_DICTIONARY:
channel_event_class = EventDictionaries.CHANNEL_EVENT_DICTIONARY[channel_event_identifier]
else:
channel_event_class = ChannelEvent
channel_event = channel_event_class()
channel_event.set_delta_time_from_bytes(delta_time)
channel_event.set_from_bytes(midi_data)
return channel_event
def close(self):
self.midi_parser.close()