I'm writing a simple MIDI parser as a learning exercise and I'd like it to interpret data piece-by-piece. Data is sent in as an iterable of integers (probably just bytes, when it's done, but I'm using a deque[int] for now).
I've currently got a simple generator-based event parser implementation, but I'm not sure what the best way is for me to actually use it, since the function yields until it's got all the data it needs, and then returns the newly-created event. So my questions are:
- Are generators a good way to do this sort of thing?
- Are there any other ways to achieve the same results?
- What's the best way to use the current implementation?
Apologies if the code isn't layed out too well.. I've not done much using generators before.
The event parser function (irrelevant parts removed):
def parse_event(last_status_byte: int | None = None) -> "Generator[None, Any, MidiEvent]":
first = yield # Get the first byte
# Do some initial processing...
if is_channel_event:
# ...
for _ in range(num_data_bytes): # num_data_bytes is calculated beforehand
data_bytes.append((yield))
# Return the newly-created event.
return channel_event_classes[event_type](...)
raise TypeError(f"Unsupported event: {status_byte:02X}.")
How I'm testing it out:
data = deque((0x90, 0x3C, 0x64))
event_generator = parse_event()
next(event_generator)
while True:
try:
event_generator.send(data.popleft())
except StopIteration as exc:
evt: NoteOnEvent = exc.value
break
print(evt.channel, evt.note, evt.velocity, evt._bytes)
Thanks. :)