Programming a MIDI file parser *and* player

Mu0n

Active Tinkerer
Oct 29, 2021
603
558
93
Quebec
www.youtube.com
Goals:
  • understand the MIDI file format specs
  • program a parser that detects every type of MIDI command, including the System Extension ones
  • program a player that digests the previous information and sends it out to a serial port so it can be consumed by an external midi device (ie a sound canvas) - ie a midi player
  • do it first inside Windows 11 using Python
  • port it to 6502 assembly and/or C so it can also work on a F256K2 (upcoming 2024)
Useful gotchas:
  • under the modern windows era, you may have to use this trick to set the MIDI out via a USB midi interface to an external MIDI module, otherwise you're stuck with the GS Synth software midi driver of windows. I made a resource about it here https://tinkerdifferent.com/resources/midi-out-setter-for-modern-windows.134/
  • Code:
    pip install rtmidi
    is my go-to python library in order to detect MIDI out ports, open the one and send commands to it for playback
  • I viewed this video, which helped understand some quirks about the MIDI format
  • This video covers a similar thing, done in dos basic, but some principles apply again

The documentation for the spec in great detail can be found here:


TO DO:
paste a github with my python code
paste another github with my F256K code (possibly 6502 asm, possibly C)
 
Last edited:

Mu0n

Active Tinkerer
Oct 29, 2021
603
558
93
Quebec
www.youtube.com
This python script can be used to quickly test out your MIDI out connection to a sound module.
It will simply play out a C major scale with the default MIDI instrument, the piano.

Python:
# Define the MIDI commands for a C-major scale
notes = [60, 62, 64, 65, 67, 69, 71, 72]  # MIDI note numbers for C4 to B4

out = rtmidi.MidiOut()
ports = out.get_ports()
print(ports)

out.open_port(1)

for note in notes:
    note_on = [0x94, note, 100]
    note_off= [0x84, note, 100]
    out.send_message(note_on)
    time.sleep(0.1)
    out.send_message(note_off)
    time.sleep(0.1)
 

Mu0n

Active Tinkerer
Oct 29, 2021
603
558
93
Quebec
www.youtube.com
a bit late but here's my github repo with the python code after a few iterations:

It can deal with:

  1. Type 0 (single track) and type 1 (multi-track) .mid files
  2. siphon off the relevant MIDI commands for playback (note on, note off, pressure, etc)
  3. parse through the relevant system exclusive (SYSEX) 0xFF commands and ignore those who don't affect playback
  4. parse through some sysex commands that are not always documented, like 0xFF 0x21 which I encountered in a .mid file I have
  5. play with the midi port of your choice, works under the GM synth of windows 11 or the external USB midi interface I have that sends out to my hardware midi modules
example video:

I can detect some slight hiccups in a tune such as human3.mid (from warcraft 1) in the middle of the tune, I still have to investigate this.

I consider the python part of the project like 98% done, I am so happy abou this.

Now, on to porting this to C and retro machines (mac first)
 
Last edited:
  • Like
Reactions: eric and YMK