MIDI to MakeCode Arcade converter…again

Introducing another MIDI-to-MakeCode-Arcade song converter!

A simple Python CLI tool that converts your MIDI files into a MakeCode Arcade song ready to play! Unlike previous versions, this tool now supports the base 128 melodic instruments in MIDI and drum notes, allowing for rich-sounding symphony/orchestra-level/DAW music directly in your MakeCode Arcade games without any extra extensions or complex code - just a (really long) song buffer!

Demos

The obligatory demos, listed below. (for a more accurate sound, use the links in the detail below that open directly in the beta editor, as per-chord velocity is still in beta) Press B to toggle the track viewer, and use arrow keys in the track viewer to highlight a track if desired.

Use these links in this detail to open the demos below in the beta editor

It is highly recommended that you open these links in incognito mode or a different browser than normal so that the beta editor is unable to interact with your regular projects or Microsoft (MakeCode Arcade) or GitHub account!

How it Works

Instrument parameter files

Expand detail to read

A 1.5k handwritten YAML file is used to define what all 128 melodic instruments and 61 drum notes sound like. Excerpts below:

melodic_instruments:
  # Pianos
  - instrument: 0
    _comment: Acoustic Grand Piano
    waveform: triangle
    amp_envelope: { attack: 5, decay: 500, sustain: 200, release: 200, amplitude: 768 }
    pitch_envelope: { attack: 0, decay: 0, sustain: 0, release: 0, amplitude: 0 }
    amp_lfo: { frequency: 0, amplitude: 0 }
    pitch_lfo: { frequency: 0, amplitude: 0 }

  - instrument: 12
    _comment: Marimba
    waveform: sine
    amp_envelope: { attack: 5, decay: 300, sustain: 0, release: 200, amplitude: 1024 }
    pitch_envelope: { attack: 0, decay: 0, sustain: 0, release: 0, amplitude: 0 }
    amp_lfo: { frequency: 0, amplitude: 0 }
    pitch_lfo: { frequency: 1, amplitude: 1 }

  - note: 38
    _comment: Snare Drum 1
    start_freq: 800
    start_vol: 300
    steps:
      - { waveform: triangle, target_freq: 100, target_vol: 300, duration: 10 }
      - { waveform: noise, target_freq: 0, target_vol: 300, duration: 10 }
      - { waveform: noise, target_freq: 0, target_vol: 200, duration: 10 }
      - { waveform: noise, target_freq: 0, target_vol: 0, duration: 40 }

  - note: 36
    _comment: Bass Drum 1
    start_freq: 120
    start_vol: 1024
    steps:
      - { waveform: sine, target_freq: 70, target_vol: 850, duration: 25 }
      - { waveform: sine, target_freq: 45, target_vol: 350, duration: 35 }
      - { waveform: sine, target_freq: 35, target_vol: 0, duration: 50 }

It follows exactly the instrument encoding for MakeCode Arcade songs:

https://github.com/microsoft/pxt/blob/master/pxtlib/music.ts#L23-L94

Then some Python scripting is used to read and map the MIDI file’s note on/off for each instrument into a song! Funnily enough, most of the effort was actually writing the instrument file by hand, as Claude’s attempt resulted in something interesting…I think I’ll let Claude and Gemini help me with coding…

What it Supports

Excerpt from the README:

Standards:

  • General MIDI 1 melodic instruments (0-127) and the standard drum kit notes (35-81)
  • General MIDI 2 extended drum note range (27-87) on the standard drum kit only
  • Roland GS/Yamaha XG SysEx messages for track switching to standard drums only

Features/MIDI messages:

  • Tempo changes
  • MIDI ports and channels
  • Common control changes and Roland GS/Yamaha XG SysEx messages to switch a track to a drum track and back (will only use the standard drum kit notes)
  • Per-note velocity (MakeCode Arcade will ignore this for now, but it’s in the song’s output - MakeCode Arcade beta at the time of writing supports it)

See src/midi_to_song/timeline/parser.py to find the exact messages and their values that are supported.

Other Tools / Versions

Here are some other similar tools you should check out!

And previous versions of MIDI in MakeCode Arcade by me (that are now basically garbage compared to this…)

  • ArcadeMIDI which uses images to convey music information and play it back with an extension. Worse performance as JS is managing notes, and less features and is less accurate.
  • Musical-Images which also uses images to convey music information and play it back with an extension. Even worse than ArcadeMIDI in every way.

Using it Yourself

To create your own MakeCode Arcade songs, follow the instructions in the README to set up and run the Python tool. (this is not a web app - you need to be able to run Python code somewhere. If you are a Chromebook user and cannot set up Linux usage, try an online environment like GitHub Codespaces, which provides a full Linux environment. Python knowledge is highly recommended - use your favorite search engine or AI assistant or post below or in GitHub issues if you need help or run into any issues!)

The GitHub repo’s README also includes instructions on creating/tuning your own instrument parameter files if desired.

If you want to use the song visualizer yourself, you can find that here (you can import it in an incognito tab/different browser in the beta editor to then paste your own song output). The code was adapted from my original piano synthesia code, which permanently borrowed code from @AqeeAqee’s Karaoke.

Enjoy!

9 Likes

So now you can create music in another editor like musescore and then convert it into makecode? Sweet!

2 Likes

yo @UnsignedArduino when i go to https://unsignedarduino.github.io/song-visualizer/ i get 404 did you forget to turn it in to a page?

1 Like

Didn’t intend on using the GitHub pages as my normal workflow was open MakeCode Arcade Beta in incognito tab, import that repo, add in song and change title, etc., and share a link and then done. I never decided to create a release because the song visualizer is a one-off thing, but thanks for letting me know.

1 Like

yo @UnsignedArduino again i get this Traceback (most recent call last):
File “/workspaces/makecode-music-convert/MIDI-to-MakeCode-Arcade/src/main.py”, line 6, in
from cli import generate_and_parse_args, generate_melodic_instrument_sample,
File “/workspaces/makecode-music-convert/MIDI-to-MakeCode-Arcade/src/cli.py”, line 9, in
from midi_to_song import InstrumentParameterMapping, TestingOptionsForMIDIToSong,
File “/workspaces/makecode-music-convert/MIDI-to-MakeCode-Arcade/src/midi_to_song/init.py”, line 10, in
from midi_to_song.instruments import InstrumentParameterMapping
File “/workspaces/makecode-music-convert/MIDI-to-MakeCode-Arcade/src/midi_to_song/instruments.py”, line 9, in
from midi_to_song.models import TestingOptionsForLoadInstrumentParams
File “/workspaces/makecode-music-convert/MIDI-to-MakeCode-Arcade/src/midi_to_song/models.py”, line 32, in
class ChannelState:
File “/workspaces/makecode-music-convert/MIDI-to-MakeCode-Arcade/src/midi_to_song/models.py”, line 37, in ChannelState
drum_determined_by: DrumDeterminationSource
^^^^^^^^^^^^^^^^^^^^^^^
NameError: name ‘DrumDeterminationSource’ is not defined
help peezzz my audio file is the it is a mid
https://zeldacentral.com/midi/spirit-tracks it is the Spirit Tracks - Fleeing by Demon Train.mid file help

Yet another one! The piano graphics are a nice touch.

1 Like

Its definitely defined cause it runs perfectly fine on my computer lol, are you in the root directory and running the program like python src/main.py ...? What version of Python are you on?

uuuhhhh what ever github codespaces is

I’ve fixed it and pushed the new code, so you can git pull or delete and reinit the codespace. Apparently Python 3.14 introduced forward references, and Codespace’s current Python 3.12 doesn’t support something like this out of the box, so a simple from __future__ import annotations fixes it.

@dataclass
class ChannelState:
    program: int  # instrument
    bank_select_msb: int
    bank_select_lsb: int
    is_drum: bool
    drum_determined_by: DrumDeterminationSource  # used before definition below


class DrumDeterminationSource(IntEnum):
    DEFAULT = 0
    CC = 1  # control change
    SYSEX = 2

Thanks for bringing this to my attention!