The music format of the AKI N64 wrestling games
How the six AKI wrestling games on the N64 store music as sequences and VADPCM samples, how the output rate was found, and whether a theme can be replaced with your own audio.
The six AKI wrestling games for the Nintendo 64 contain almost no recorded music. Each song is a list of notes and commands that a small player routine plays with a bank of short samples. I read all six cartridges with my own tool to see how the format works.
What a song is#
When No Mercy plays its title theme, nothing on the cartridge is a recording of it. The cartridge holds a sequence, a list of instructions such as "play note 52 for 24 ticks" or "switch to instrument 7", and a sample bank, the short sounds those instructions play. A player routine reads the sequence sixty times a second and mixes the result, much like a tracker module.
This is why the music fits at all. No Mercy's 27 songs take 145,782 bytes of sequence data and run for 39.6 minutes. As a 128 kbit/s MP3 the same music would be 38,016,000 bytes, or 36.3 MiB, more than the whole 32 MiB cartridge. Most of the space goes to the samples: across the six games, sequence data ranges from 99,267 to 316,742 bytes and sample data from 2,307,018 to 12,504,447 bytes.
A track is read one byte at a time. A byte below 0x80 is a note (0x60 is a rest), followed by its length. A byte from 0x80 to 0xAC is a command:
byte < 0x80 a note; 0x60 is the rest
[velocity] one byte, only while velocity mode is on
length 1 byte if < 0x80, else 15 bits over 2 bytes
byte >= 0x80 a command, 0x80..0xAC
0x81 wave n pick the instrument (the sample) for this channel
0x8B fixed_length use one length for every note that follows
0x90 envelope n load envelope n from the song's envelope table
0x95 loop_start c repeat the next stretch c times; 0xFF means forever
0x9C pan p p >> 1, so 0..127 over the stereo field
0xA6 volume v
0x80 stop end of trackThe tool counts a track as read only if it ends in stop or in an endless loop with no bytes left over, and 138 of 142 songs and effect banks across the six cartridges meet that standard. Of No Mercy's 27 songs, 25 loop forever, the longest running 486.1 seconds before it repeats. No song in the first two games loops, because their player has no loop of that kind.
VADPCM samples#
Every sample is stored as VADPCM, the N64's own compressed audio format, which the RSP (the console's signal coprocessor) decodes during playback. It is a small predictive codec with no psychoacoustic model. Instead of discarding what the ear cannot hear, it stores a prediction and a coarse correction.
A frame holds 16 samples in 9 bytes. The first byte carries a 4-bit shift and a 4-bit index into a codebook, and the other eight hold 16 signed 4-bit residuals. Each sample is predicted from the two before it, using the coefficient pair the index selects, and the residual, scaled by the shift, is added. The codebook is stored with each sample. In Revenge and No Mercy every sample uses four predictors of order 2, while one World Tour bank has 70 samples with eight.
16-bit PCM 2 bytes per sample
VADPCM 9 bytes per 16 samples = 0.5625 bytes per sample
a fixed 3.556 : 1, every frame
at 28,800 Hz 16,200 bytes per second (raw: 57,600)
so 1 MiB = 64.7 s 1 MB = 61.7 s
30 s = 486,000 B 3 min = 2,916,000 B
at 7,200 Hz 4,050 bytes per second, the rate entrance themes play at
1 MiB = 258.9 s 30 s = 121,500 BThe decoder can be checked against the ROM itself. A looping sample stores the 16 predictor samples the game saved at its loop point, so the hardware can jump back without a click, and the decoded frame at that offset must match them. No Mercy passes 66 of 66, Revenge 24 of 24, WrestleMania 2000 63 of 63 and VPW2 27 of 27. The first two games store no loop points, so there is nothing to check.
Finding the output rate#
In World Tour and Virtual Pro-Wrestling 64 the rate is a constant. The tool finds osAiSetFrequency by its shape (it touches the audio interface registers and clamps its argument at 132) and reads the one value its callers load: 22,050.
The other four games use a different audio library. There the rate sits in a configuration structure that the game builds at start-up and passes to MusInitialize. Pattern matching near the call finds a plausible value, but that only counts as likely. To confirm it, the tool maps the audio interface registers into a fake address space, sets up the configuration and runs MusInitialize in a MIPS interpreter until the game writes the hardware register itself. That takes 352,520 instructions in No Mercy, 901,342 in Revenge and 624,220 each in WrestleMania 2000 and VPW2. All four request 28,800 Hz.
Two more checks turn the request into the rate the hardware plays. The N64 derives its audio timing from the video clock, which depends on the TV standard. The tool runs every branch on osTvType with types 0, 1 and 2 and accepts only a site that yields three different plausible clocks; all six cartridges give 48,681,812. In No Mercy, calling osAiSetFrequency with 28,800 writes AI_DACRATE = 1689, a divider of 1690. The game therefore plays at 48,681,812 ÷ 1690 = 28,805.8 Hz, 0.02 % or about a third of a cent above the request. In the first two games, 48,681,812 ÷ 2208 = 22,047.9 Hz against a requested 22,050.
The command set#
The player dispatches commands through a table of function pointers, which the tool finds as a run of 43 to 64 consecutive words pointing into the boot segment. In No Mercy it sits at 0x80052E74. Each handler is then called in the interpreter on a fake channel structure, with known values and known argument bytes.
Running a handler with 0x01 bytes and again with 0x81 bytes shows how many argument bytes it consumes. All 45 handlers in No Mercy, WrestleMania 2000 and VPW2 match the format, as do all 43 in Revenge. Running it with five argument sets and comparing the channel before and after shows which field it writes and with what formula. A command is confirmed only when field and formula agree in all five runs. No Mercy has 22 confirmed, 18 likely and 5 that do not touch the channel (stereo, print, start_effect, change_effect and marker). Revenge gives 22, 17 and 4.
tempo ticks_per_frame = trunc(trunc(bpm * 24576 / 120) / 60)
four tempos; channel field 156 in No Mercy, 188 in Revenge
envelope 7 bytes: rate, start, attack, peak, decay, sustain, release
rateDiv = trunc(1024 / rate), confirmed with three entries
curve level = base +/- trunc(slope * ((ticks * rateDiv) >> 10))The curve formula was written first, for the tool's renderer. A separate search later found a function in the ROM that computes the same curve, with all three phases, in each of the four later games. The renderer also agrees with the effect table on all six cartridges: 39 commands, 75 field bindings, 0 mismatches.
How the six games differ#
The engines split two and four. World Tour and Virtual Pro-Wrestling 64 use the N64 SDK's own audio library, libultra, with cseq sequences and ALBankFile banks at 22,050 Hz. Revenge already uses the player the tool labels libmus, with sng sequences and PtrTablesV2 banks at 28,800 Hz, the same engine as the three later games. Its command table is one revision older, with 43 entries instead of 45.
| World Tour | VPW64 | Revenge | WM2000 | VPW2 | No Mercy | |
|---|---|---|---|---|---|---|
| Product code | NWNE | NVPJ | NW2E | NWXE | NA2J | NW4E |
| Cartridge | 12 MB | 16 MB | 16 MB | 32 MB | 32 MB | 32 MB |
| Player | libultra | libultra | libmus | libmus | libmus | libmus |
| Output rate | 22,050 | 22,050 | 28,800 | 28,800 | 28,800 | 28,800 |
| DAC divider | 2208 | 2208 | 1690 | 1690 | 1690 | 1690 |
| Rate the hardware makes | 22,047.9 | 22,047.9 | 28,805.8 | 28,805.8 | 28,805.8 | 28,805.8 |
| Sequence format | cseq | cseq | sng (43 cmd) | sng (45) | sng (45) | sng (45) |
| Bank format | ALBankFile | ALBankFile | PtrTablesV2 | PtrTablesV2 | PtrTablesV2 | PtrTablesV2 |
| Banks | 2 | 2 | 2 | 3 | 8 | 3 |
| Samples | 263 | 300 | 201 | 238 | 516 | 293 |
| Bytes of VADPCM | 2,307,018 | 2,481,370 | 2,939,913 | 9,228,150 | 12,504,447 | 9,054,513 |
| Songs | 19 | 28 | 21 | 16 | 19 | 27 |
| Effect banks | 0 | 0 | 1 | 2 | 7 | 2 |
| Notes | 25,374 | 42,053 | 54,006 | 44,788 | 46,461 | 36,201 |
| Events | 27,450 | 44,735 | 122,242 | 99,195 | 104,967 | 70,252 |
| Channels per song | 2–8 | 2–8 | 7–19 | 10–18 | 7–19 | 4–18 |
| Longest song | 171.8 s | 173.5 s | 442.0 s | 389.3 s | 389.3 s | 486.1 s |
| Songs that loop forever | 0 of 19 | 0 of 28 | 19 of 21 | 15 of 16 | 18 of 19 | 25 of 27 |
| Bytes of sequence | 99,267 | 159,356 | 316,742 | 229,090 | 232,804 | 145,782 |
| Longest sample at base pitch | 6.128 s | 6.128 s | 4.591 s | 19.412 s | 46.323 s | 23.307 s |
| Command meaning | — | — | 22/17/4 | 22/18/5 | 22/18/5 | 22/18/5 |
| Parse status | 19 conf. | 28 conf. | 22 conf. | 18 conf. | 23 conf., 3 likely | 28 conf., 1 likely |
| Bank assignment | 19 likely | 28 likely | 22 conf. | 18 conf. | 26 conf. | 29 conf. |
A few differences stand out:
- Revenge packs in the most: 316,742 bytes of sequence and 122,242 events on a 16 MB cartridge, more than any of the 32 MB games, with songs of up to 19 channels.
- VPW2 has the most samples: 516 in 8 banks, 12,504,447 bytes in all, plus 7 effect banks.
- No Mercy has the leanest sequences: 39.6 minutes in 145,782 bytes, less than half of Revenge's.
- World Tour and VPW64 have no binding in the code that ties a song to its bank, so the tool matches them by fit and the result stays likely, even though only one bank fits each song.
Using the tool#
In AKI Anvil, the Music tab lists every song and effect bank of your own dump, read in the browser without uploading anything. Songs play through the tool's own sequencer, every sample can be played on its own, and both can be saved as WAV files. For No Mercy and WrestleMania 2000 the same tab lists the entrance themes, and each one can be replaced with your own audio. Still missing are MIDI export and a measured mixer for exact renders.
Can you replace a theme with an MP3?#
An MP3 cannot become a sequence, but a theme can be one long sample played as a single note, and three of these games already work that way. Three things have to hold.
A long enough sample#
No Mercy's third bank has 43 long samples, 42 of them looping, in 6,541,578 bytes. WrestleMania 2000's has 45, all looping, in 6,511,518 bytes. VPW2's third bank holds ten samples of equal length, 7,504,056 bytes in total, each looping over nearly its whole length. The format sets no limit beyond a 32-bit byte count.
One note to play it#
An effect bank is a table of very short sequences, one per sound. No Mercy's second effect bank has 200 entries with exactly one note each: pick a wave, set an envelope, pan and volume, play the note, stop. A note can last up to 32,767 ticks, the largest two-byte length, which is 341.9 seconds at the base tempo. WrestleMania 2000 has 90 such entries over its 45 long samples, and VPW2 has 20 over its ten.
The note also sets the speed. In No Mercy and WrestleMania 2000 it sits two octaves below the sample's base pitch, so every theme plays at a quarter of the output rate: 7,200 Hz. At that rate No Mercy holds 1,615.2 seconds of themes, the longest 93.2 seconds, and WrestleMania 2000 holds 1,607.8. No Mercy plays each theme on four voices, two left and two right, with the right pair four ticks late; WrestleMania 2000 uses two, hard left and hard right, two or three ticks apart. Seven of No Mercy's 50 theme numbers play a sequenced song instead. VPW2's notes play its ten samples at 22,208 Hz, 60.1 seconds each, but which wrestler gets which is not mapped yet.
Space on the cartridge#
A theme longer than the one it replaces needs more room. The Overview reports the 0xFF padding at the end of each cartridge and checks that no code address points into it. The tool keeps the last 4,096 bytes free and can use the rest. At 4,050 bytes per second, that space holds:
| Cartridge | Free bytes at the tail | Seconds at 7,200 Hz |
|---|---|---|
| WrestleMania 2000 | 5,797,104 | 1,430.4 s |
| World Tour | 1,299,232 | 319.8 s |
| VPW2 | 768,592 | 188.8 s |
| No Mercy | 365,808 | 89.3 s |
| Revenge | 259,456 | 63.1 s |
| VPW64 | 191,440 | 46.3 s |
The answer#
Yes, and in No Mercy and WrestleMania 2000 the tool does it. Drop an audio file on a theme in the Music tab: the browser decodes it and resamples it to 7,200 Hz, the tool mixes it to mono, encodes it as VADPCM and writes it over the old sample, or at the end of the cartridge if it is longer. A 30-second theme costs 121,500 bytes and a three-minute one 729,000. In No Mercy a new theme may run as long as the old one or fill the free space, whichever is more: 89.3 to 93.2 seconds for the first theme you replace. A longer file is cut with a short fade. WrestleMania 2000 has room for almost 24 minutes.
Mono costs little here, since the game spreads the one sample over both speakers itself. For comparison, a 128 kbit/s MP3 spends 16,000 bytes per second on stereo at 44.1 kHz, while a theme spends 4,050 on mono at 7.2 kHz. The low rate has a price: nothing above 3,600 Hz survives, about what a telephone line carries.
The music in these games is written down rather than recorded: a few hundred kilobytes of notes, a few megabytes of samples, and a player that turns one into the other sixty times a second. That is also why all of it can still be read back out today.
How I measured this#
All figures come from dumps of my own cartridges, read with AKI Anvil on 11 September 2026, and the theme figures again on 25 September 2026; no ROM data is reproduced here. What each command does was measured by running the game's handlers in a MIPS interpreter, the same one used for the pin mechanic and the engine ranking.
| Cartridge | Code | SHA-256 |
|---|---|---|
| WCW vs. nWo: World Tour (USA, rev A) | NWNE | 3711c8838b18374d1c7be0192ad824082d33978f00b886d145bc55a782325d4d |
| Virtual Pro-Wrestling 64 (Japan) | NVPJ | 8b7191ae5489fc71c7a18c05a0afba035a88d8f22a2b047253dd9c524fb88921 |
| WCW/nWo Revenge (USA) | NW2E | 66c137d326565c6f31f992daba8f67c0aee7f025a142dd249d27019708014b60 |
| WWF WrestleMania 2000 (USA) | NWXE | cbd44033868d3747241f5028206056e64836d744c756b5c39dc7b3a446e8ce5b |
| Virtual Pro-Wrestling 2 (Japan) | NA2J | 358e9a345438155c6bd57da4bbf0f7a9fa1b4f7d5b1b726e8076c38f0f987e52 |
| WWF No Mercy (USA, rev A) | NW4E | fc561fce443010b114cc8ea41226772b7b2a2d33055be163fad91ac9c3b096cb |