Off-by-one skips second song when first played.
There's a flaw in the message/block mechanism of the startAudio() function. When the scheduler calls startAudio() to start the next block of notes/events, it passes in the queued time which becomes the current time. The skipping loop then stops at this same time and will repeat the same last note played. Offsetting the startAudio() call by 0.5 ms fixes this, but this leads to skipping any other notes that play at that same time. To fix this, you need to play all notes at the same cutoff time, so that the next iteration will start playing any events after that particular time reference.

This is hard to detect at a limit of 100 messages, but is easy to see at a limit of 4 messages. I'll include test-MIDIPlayer.html which is a bastardized version of demo-MIDIPlayer.html with three songs of quarter notes that can reproduce the problem.
Song one is just four notes in 4/4 time.

Song two is the same but plays a chord on the third beat. The chord is perfectly sychronized on the 3rd beat.

Song three is the same as two but with an extra note on the third beat one tick behind the chord. This is to test that that note is still picked up after processing the chord together as part of the block.