Okay, work went a bit late and I watched some long videos, so it's too late already.
As such, I'm going to just jot down some thoughts on representing chords. There are a few different things that "a chord" can mean, and a few different ways that those realizations could reasonably be represented in MIDI.
Classically speaking, if I remember my lessons from ten years ago correctly, the important aspects of a chord are the root, the third, and the tone that the bass is playing/singing. Considering a cord in isolation, it can either be several tones that start and end simultaneously, relatively stable in the lower voices but more elaborate in the upper voices, or stable in the middle voices but elaborate in the outer voices. This stability can last across multiple chords. What this means is... "how should I represent a bunch of notes in complete lockstep" is probably not a question I should try to answer, because there usually isn't a reason to do that a lot. (Unless I decide to bring back Theory by Exhaustion or whatever it was called. (Wait, did I make that post, or just think about it? I'm not seeing it when I search...))
So, the "right thing", I think, is to figure out how to represent a framework of timing events, and then have my code subscribe to that framework. I could then do stuff like coordinate tempo changes through that framework, and have a bunch of things "just work".
Thought on how to do that, relatively unpolished: awaiting a synchronization object produces a new object representing the "final time", and that provides an async method that takes a note length. It should also be possible to wait for events like "the next bar after this time point" or "a named section".
The way to tell whether that's workable or painful: transcribe music into that framework, and see what I think.
Anyway, I've taken way too much time on this.