I used two separate libraries, one to convert the MIDI file into an in memory representation and Vexflow, then a whole pile of glue (not the nicest part of the code) to combine the two.
There are some aspects of that that I want to revisit such as the automatic recognition of decorations (for instance: trills) so that they can be shown properly but these are tricky problems and I want to avoid spending more time on pianojacq.com than on using it.
Lately I've added an ear training module but I'm not completely happy with it yet (hit Bb0 to enable a hidden menu if you want to play around with it).