New Song format

I just remembered that I promised @UnsignedArduino that I would make a post linking to the new song format! Well, better late than never.

The format of the song buffer is documented here:

That file also contains all of the code for encoding/decoding the songs from buffers (in this case, uint8Arrays). The default instruments are all defined in the getEmptySong function.

This code is mirrored in the arcade game engine here:

If I were, hypothetically, making a webapp that converted midi files into the new song format, then I would:

  1. Copy all of this file
  2. Also copy these two functions

there are also a bunch of utility functions for manipulating songs here:

4 Likes

Once I’m done doing hot fixes, I will write some proper docs explaining the format in more detail!

3 Likes

Thank you so much! I definitely did not waste an entire day converting that entire first file you linked to Python first. :clown_face: :clown_face: :clown_face:

2 Likes

One other thing I just thought of, note events for tracks need to be sorted by the start tick (e.g. they need to be encoded in chronological order).

2 Likes

Also one question: I have code like this:

song.tracks[0].notes.append(
    NoteEvent(
        notes=[
            Note(
                note=49,  # Lowest C in octave
                enharmonicSpelling=EnharmonicSpelling.NORMAL
            )
        ],
        startTick=0,
        endTick=8
    )
)

Why is 49 “middle C?” Is it a MIDI note index? Or something else?

1 Like

yup! the numbers are midi note numbers

2 Likes

Hi @richard, sorry to bother you but right now, I’m having difficulty with the instrument octaves. I’m setting the octave to 2 here:

I’m using a test MIDI file that has a glissando of notes from MIDI note 21 to 108, the lowest and highest notes on a piano. For some reason, the notes appear to be “shifted” by a couple of octaves. You can hear it here:

Do you have any idea why? I’ve tried other octaves like 0, 1, and 3 but they all produce shifted ranges too. Do I have to split up the notes to separate tracks that handle instruments with different octaves?

Progress update I guess:

Reload the page if you want to stop the song, because restarting the simulator doesn’t stop the song for some reason.

4 Likes

Yeah, known bug… Not sure when it started.

2 Likes

Also WOW the song editor cannot handle that. Might have to look into re-implementing it…

2 Likes

(self-promotion hehe)

The Python tool is mostly done, I only need to iron out a couple of bugs:

I will be working on a web-based version.

2 Likes

Are you saying there’s another way I can make music? :face_with_raised_eyebrow:

2 Likes

Yes! My script can convert a .midi file (which can be exported from any music score editor) to MakeCode Arcade’s new(ish) song format! It works much better than ArcadeMIDI and Musical-Images and does not use an extension.

2 Likes

The reason is here, I guess:

The “& 0x3f” masked off notes range to 0~63+octave*12, so whatever the octave set it can’t arrange 88 difference notes. So need 2 instruments at lease, 2 tracks as well(each track contain only 1 intrument).

1 Like

Thank you so much!!! I just fixed the converter so that all the high notes work.

1 Like

Hi @richard sorry to bother you, but I can’t seem to find the declaration of U: (which I’m assuming is the same as pxt.U)

  export function encodeSongToHex(song: Song) {
    const encoded = encodeSong(song);
    return U.toHex(encoded);
  }
  export function decodeSongFromHex(hex: string) {
    const bytes = pxt.U.fromHex(hex);

    return decodeSong(bytes);
  }

Is it a namespace of utility functions?


1 Like

It’s the same as the pxtc.Util namespace. Declared here: https://github.com/microsoft/pxt/blob/master/pxtlib/main.ts#L31

And here is that function:

2 Likes

How can i use this?

Dude. WHAT AM I EVEN LOOKING AT. Seriously, some people are just too smart.

2 Likes

Makecode source code! :smiley: