These are the specifications I've used for Mario 64 Sequenced Music Parser v0.07. They are in most part valid also for
all first-party Nintendo 64 titles, such as Super Mario Kart 64, Wave Race 64, Starfox 64, Zelda 64, Yoshi's Island
nad others 1080 Snowboarding and a few others.There might be a few variations between each game.
Thanks to rstewart215804 for and DJBouche for some earlier notes posted at the Jul SM64 Hacking Forum.
All offsets are for the Super Mario 64 1.0 US ROM. Other versions may use slightly different commands.
The sequence bank starts at 0x7B0860. First four bytes may be some sort of "revision number" (2 bytes) and sequence count (2 bytes).
After this, follow a list of pointers. Format is: start offset (4 bytes) + lenght (4 bytes). You can use the seq_rip.exe utility to extract all
sequences from a Mario 64, Mario Kart 64 or Wave Race 64 ROM.
"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 (ie, eight 4/4 bars)
separated by variable-lenght timestamp commands (0xFD). The first command is always 0xD3, followed by parameter 80, 60 or 20.
"Track" Format and Commands Table
A different set of commands is used when processing the track data, but they are very similar to the header ones.
Music Events Table
This is the format for the data pointed by the Track Data 0x90 - 0x9F commands.
Timestamp (Variable-lenght - 1 or 2 bytes)
0x10 = Triplet
0x18 = Eight-note
0x30 = Quarter note
0x60 = Half-note
The first bit indicates variable lenght timestamp. If any valuer higher or equal to 0x80 is used, an additional byte is read, ie:
0x8C00 = 0xc00 timestamp.
0x9C00 = 0x1c00 timestamp.
The table that determines which instrument set is used in each sequenced is located at 0x7cc620:
The blue bytes consist of 0x23 halfwords (2 bytes), which is the same number of sequences in the ROM. Each entry is actually
a relative pointer to the 'instrument set' used by that sequence. To read the table, just use the sequence
number * 2 (halfword) + 0x7cc620 (start of the table).
0x01 and 0x11 are actually two separate bytes, not an halfword. I'm not sure if the first one is also an instrument set, but the second
one certainly is. So, this sequence uses instrument set 0x11 (in decimal = 17).
This number relates to the "NInst" instruments in the .ctl file. Using srip (download from dextrose.com), you can extract all (or most)
sounds in the ROM and it outputs a control.h file which includes information about the sound structs used in the game in a
sort of reconstructed .ctl file.
There are 37 NInst entries (0x25). Each one of these contries contain an index to the individual instrument sounds.
SRIP outputs all sounds in the format A00 + Ninst number (00 to 37) + sound index.
Here is NInstrument NInst17 (0x11), the Title Screen SMB Music instrument set:
Sound1700, 0x00 = Snare Drum
Sound1701, 0x01 = Fingered Bass
NULL, 0x02 = NULL = same as last one (0x01)
Sound1703, 0x03 = Organ
Sound1704, 0x04 = Steel Drum
Sound1705, 0x05 = Trumpet
Sound1706, 0x06 = Slap Bass
Sound1707, 0x07 = Synth
Sound1708, 0x08 = Clavinet
NULL, 0x09 = NULL = same as last one (0x08)
Sound1710, 0x0A = Drum Sample (hi-hat)
Sound1711, 0x0B = Drum Sample
Sound1712, 0x0C = Drum Sample
Sound1713, 0x0D = Drum Sample
Other instrument sets:
NInstrument NInst 15
Used in: Lethal Lava Land (sequence #6)
00: Simple percussion loop
01: Voice 'Uhs'
02: Sitar drone notes
03: Sitar melody
Used in: Inside Castle (sequence #6)
Sound1400, 0x00 = Strings
Sound1401, 0x01 = ?
Sound1402, 0x02 = ?
Sound1403, 0x03 = Pizzicatto string
Sound1404, 0x04 = Cello? (or low and deep woodwind?)
Sound1405, 0x05 = Eletric Piano
Sound1406, 0x06 = ?
This is the index used inside the Title Screen Music (for the 0xC1 instrument command, or '@' in mml2m64).
Default instrument sets
Seq. Bank. related code (DMA)
80319714: LUI A0, 0x007B
80319718: SW A1, 0x0000 (V0)
8031971C: ADDIU A0, A0, 0x0860
80319720: JAL 0x80318040 # BlockDmaCopy function
80319724: ADDIU A2, R0, 0x0010
80319768: LUI A0, 0x007B
8031976C: SW V0, 0x0000 (V1)
80319770: ADDIU A0, A0, 0x0860
80319774: OR A1, V0, R0
80319778: JAL 0x80318040 # BlockDmaCopy function
8031977C: OR A2, S0, R0
80319780: LUI A0, 0x8022
80319784: LUI A1, 0x007B
80319788: ADDIU A1, A1, 0x0860 # alSeqFileNew function
8031978C: JAL 0x80325CD8
This code process Track Header commands:
You can place a breakpoint at 0x8031DC74 to see how some of the header commands
are processed. This specific point checks if the byte is 0xFF (end of header).
You can step through the code to see how some commands are processed.
8031DC74: ADDIU AT, R0, 0x00FF
8031DC78: ANDI A3, V0, 0x00FF
8031DC7C: BNE V0, AT, 0x8031DCB8 # V0 = current byte from sequence header
8031DC80: OR A0, V0, R0
8031DC84: LBU V1, 0x0018 (S0)
This is one function that reads Variable Lenght values (for timestamps):
8031C080: LW V0, 0x0000 (A0) ; ReadVarLen() function (1 or 2 bytes)
8031C084: LBU V1, 0x0000 (V0)
8031C088: ADDIU T6, V0, 0x0001
8031C08C: SW T6, 0x0000 (A0)
8031C090: ANDI T7, V1, 0x0080
8031C094: BEQ T7, R0, 0x8031C0BC
8031C098: OR A1, V1, R0
8031C09C: LBU T0, 0x0000 (T6)
8031C0A0: SLL V1, A1, 0x8
8031C0A4: ANDI T9, V1, 0x7F00
8031C0A8: OR V1, T0, T9
8031C0AC: ANDI T1, V1, 0xFFFF
8031C0B0: ADDIU T2, T6, 0x0001
8031C0B4: SW T2, 0x0000 (A0)
8031C0B8: OR V1, T1, R0
8031C0BC: JR RA
8031C0C0: OR V0, V1, R0