====== SM64 Music ======
===== Specification =====
These are the specifications for the data formats to store music in the SM64 ROM. They are common across many first-party Nintendo 64 titles, such as Mario Kart 64, Wave Race 64, Starfox 64, Zelda 64.
Work on reversing this specification roughly took place in three phases:
* Early 2000s: Messaien64 and Deathbasket. This is the version of the format shown on this page. Basic structure and most music-related commands. There wasn't enough information known to reliably export sequences, but sequences could be imported without too many errors. There was early software written to import sequences with one voice per MIDI channel.
* 2014-2017: Sauraen. Developed full MIDI importer/exporter, https://github.com/sauraen/seq64 . The definitions of the sequence file format is user-editable within the program, not hard-coded, so you can just view all the command definitions (like they are listed below on this page) within the GUI. Began to reverse engineer the scripting capabilities of the file format but was not able to figure out many of the scripting-related commands.
* 2019: Simon Lindholm. Complete list of all scripting commands: https://hackmd.io/opEB-OmxRa26P8h8pA-x7w Most are fully understood but some still are not fully.
==== Sequence Bank ====
The sequence bank starts at 0x7B0860. The format of the sequence bank header is shown in the following table.
^ Offset ^ Length ^ Description ^
| 0x00 | 2 | Revision number? |
| 0x02 | 2 | Sequence count |
| 0x04 + N*8 | 4 | Start offset of sequence N |
| 0x08 + N*8 | 4 | Length of sequence N |
==== Header Format and Commands Table ====
The sequence header consist of pointers for all tracks, tempo, volume and loop settings. Each sequence is usually divided in chunks (i.e., eight 4/4 bars) separated by variable-length timestamp commands (0xFD). The first command is always 0xD3, followed by parameter 80, 60 or 20.
^ Byte ^ Parameters ^ Description ^
| 0x90 - 0x9F | Offset (2 bytes) | Points to track data for a specific channel, indicated by the second nibble of status byte |
| 0xD3 | M64 flags (1 byte) | Used to enable specific flags, 0x80 for M64 to pause when the music does.|
| 0xD6 | Channels (16 bits) | Disable channels flag. Each bit = one channel |
| 0xDB | Master Volume (1 byte) | Master Volume (unsigned integer) |
| 0xDD | Tempo in BMP (1 byte) | Tempo setting (BPM) |
| 0xD5 | 16 bits | Channel priority set for SFX to overtake channel when played |
| 0xD7 | Channels (16 bits) | Enable channels flag. Each bit = one channel |
| 0xFD | Variable-length (1 or 2 bytes) | Timestamp (used between track chunks and to ensure right looping), for two bytes long, add 0x80 to the first bit, for example, timestamp at 10 50 would be FD 90 50|
| 0xFB | Offset (2 bytes) | Loop from the specified offset |
| 0xFF |No param | End of header |
==== Tracker Format and Commands Table ====
The track data commands are very similar to the header ones.
^ Byte ^ Parameters ^ Description ^
| 0x90 - 0x9F | Offset (2 bytes) | Loads music data (divided in "layers"). Since simultaneous notes (using a "0" timestamp) aren't possible, many layers are loaded and played simultaneously. The second nibble of the status byte indicates the layer number |
| 0xC1 | Program (1 byte) | "Set program" related. There isn't a master index for instruments, this seems to refer to the current set of instruments, which is not specified in the sequence data but loaded by something external to it. Drums tracks usually use program 0x7F (127). |
| 0xC2 | Transposition (1 signed byte) | Transposition in semitones |
| 0xC4 | No Param | Mark the beginning of track data |
| 0xD3 | Pitch bend (1 byte) | Pitch Bend (signed integer) |
| 0xD4 | Reverb (1 byte) | Dry/Wet |
| 0xD8 | Vibrato (1 byte) | Vibrato range |
| 0xDC | unknown (1 byte) | Drum-related? |
| 0xDD | Pan (1 byte) | Set pan for this track (01 = left, 64 = center, 127 = right) |
| 0xDF | Track Volume (1 byte) | Volume for this track (unsigned integer) |
| 0xFD | Variable-length (1 or 2 bytes) | Timestamp (used between track chunks and to ensure right looping) |
| 0xFF | No Param |End of Track Data |
==== Music Events Table ====
This is the format for the data pointed by the Track Data 0x90 - 0x9F commands.
^ Byte ^ Parameters ^ Description ^
| 0x00-0x3F | Timestamp (1 or 2 bytes). Velocity (1 byte). Duration (1 byte) | "Play Note" commands ('Type 0'). Unlike MIDI, 0 = A0. Timestamp is variable length (see below). Duration byte seems to be timestamp before "NoteOff" (I'm not sure about this) |
| 0x40-0x7F | Timestamp (1 or 2 bytes). Velocity (1 byte). | "Play Note" commands ('Type 1') Duration = previous specified (producing more compact data) |
| 0x80-0xBF | Velocity (1 byte). Duration (1 byte) | "Play Note" commands ('Type 2'). Timestamp = previous specified (producing more compact data) |
| 0xC0 | Timestamp (1 or 2 bytes) | Timestamp used for rests |
| 0xC2 | Transposition (1 byte) | Transposition in semitones. Since the 'PlayNote' commands just cover a range of 0x40 notes (as opposed to 0x7F possible MIDI notes), this is used to shift the range when needed |
| 0xE0 - E8 | ? | ? |
| 0xFC | 2 bytes | Jump (used for loops). There isn't a loop counter, so the command is repeated. Offset is relative to individual sequence start |
| 0xFF | No Param | End of music track / Return from jump |
=== Timestamp Parameter ===
The variable length timestamp parameter comes in two forms:
- Fixed values:
* 0x10 = Triplet
* 0x18 = Eight-note
* 0x30 = Quarter note
* 0x60 = Half-note
- Variable length timestamp. If most significant bit (0x80) is set, an additional byte is read, e.g.:
* 0x8C00 = 0xC00 timestamp
* 0x9C00 = 0x1C00 timestamp
==== Instrument Sets ====
The table that determines which instrument set is used in each sequence is located at 0x7CC620.
===== References =====
* http://www.smwcentral.net/?p=viewthread&t=81896
* http://origami64.net/showthread.php?tid=312
* https://sites.google.com/site/messiaen64/mario-64-sequenced-music-specification
* https://sites.google.com/site/messiaen64/parsed-music-files