I believe your 28x9x-series UART has a 16-byte hardware FIFO for each send and receive channel. This would effectively absorb variations in your processing time, because it can hold a full 5 MIDI messages without waiting for them to be sent over the wire first. If you have one of the versions with 8-byte FIFOs, then it'll hold 3 messages (first byte goes to the TX shifter immediately and doesn't count against the limit) before you start busy-waiting.
So you could probably handle about 15 MIDI events in one tick before a subsequent timer interrupt would be lost, but you could only handle at most 5-6 events in the immediately following tick before the timer interrupt after that was lost. Every unused event in that quota recharges your peak 15-event handling capacity, as your ISR first catches up with real time and then your UART's FIFO drains. Conversely, if *every* tick has more than 5 events in it, you'll gradually fall behind and regularly lose some proportion of timer interrupts (but if your MIDI file is so dense that you can't physically send it over the channel fast enough, there's nothing you can do about it).
If you implement a circular buffer with 255-byte usable capacity, you'll be able to store exactly 83 events in it and a further 5 in the hardware FIFO, without even *beginning* to run behind the timer. Since it'll take about 16 ticks to completely drain that buffer, it should be enough. I advise aborting playback and displaying an error if you overflow the buffer, so that you know if you need to implement even more heroics - such as the improved timer below.
…why play those MIDI files correctly on a PC, is that because they have proper IRQ based UART routines?
If it's using a softsynth or sending the data directly to the soundcard, then it's not having to stuff the data through a narrow channel along the way. This eliminates that particular timing pitfall entirely. But if it is sending over a physical MIDI cable, then it'll be implementing a decent send buffer as described above.
Mostly, PC-based software is only indirectly IRQ-driven, unless it lives in the kernel (as a UART driver would). Timer and other interrupts can cause userspace processes to be woken up. But that's a completely different level of software complexity which you don't need to think about on a 6502.
It'll also probably be using a more sophisticated timer routine which can recover from falling behind. This is partly because the timer-hardware driver is itself kernel software and merely provides an operating system service. We could implement a better timer too, just for the exercise - you'll still want the interrupt-serviced send buffer, otherwise you'll eat a lot of CPU time busy-waiting every time you get a "dense tick".
You'll need two status bytes in RAM for this. One becomes a mutex, preventing you from re-entering the MIDI ISR while it's still working on a previous tick's data. The other allows you to count how many timer interrupts have occurred without being serviced (yet) by the MIDI ISR. Then, just before entering the MIDI ISR proper, you set the mutex and clear the interrupt mask, then clear the mutex just before you leave the ISR. You also need to decrement and test the timer counter, and loop back to service the next tick if it's already become due. (If it's an empty tick, you might only need to decrement the delta counter, but you won't know that until you've finished processing the first tick.)
This is now in the realm of "concurrent programming", so the order in which you do things matters, and it also matters whether you use an atomic operation or temporarily set the interrupt mask flag when checking or updating a shared variable. But because you do the heavy lifting with interrupts unmasked, timer interrupts won't get ignored for so long that they get lost, and you can let the UART servicing routine drain the buffer while you're still filling it, and just busy-wait if the software buffer becomes full (which should be rare, perhaps only at the very beginning of a file with a lot of setup work).