Adding Songs to FireRed: A Dreadful Tutorial
Music sets the tone of a scene. It can add power and substance to a
locale. In Ruby and Sapphire, music turned an ordinary mountainous
forest into an epic demonstration of nature-based environment design. It
has singlehandedly given meaning and impact to some of the most iconic
locations in the Pokemon series. (Would Lavender Town have been as
memorable without its somber, bereaved melodies?)
Hacking music is extremely difficult. Hopefully, this tutorial will make things a bit easier. Before we start, a disclaimer.
Disclaimer
To be perfectly honest, I'm still learning as I go. There are definitely
some better ways to do the things I demonstrate in this tutorial.
Don't take this as a 100% complete, perfect guide. Take this as a
music-hacking-newbie's attempt at consolidating several inconsistent,
outdated, and hard-to-find resources into one easily-accessible thread.
Take this as a place to start your own research and experimentation. A starting place. A stepping stone. It's not the best way to add songs. Heck, it's not even a
good way. But it's
a way, and hopefully that'll be enough for you to figure out a better way on your own.
(The alternative to this tutorial is many frustrating hours' worth of
Google searches. As opposed to this tutorial which, though terrible, is a
lot faster and you know in advance that you'll get
something out of it. So there's that.

)
I
do plan on eventually getting better with music, and then giving this tutorial a much-needed overhaul.
And now that that's out of the way...
Requirements
Here are the things you will need to follow this tutorial. Do not
attempt to install them until you have read the brief notes after the
list.
Sappy can be notoriously difficult to install properly. I will provide
instructions and download links to it in the tutorial. Links will not
provided for Mid2AGB and I would not recommend asking for them. (I've
heard that it was leaked from Nintendo's own coding environment. I don't
know if that's true. I'm not chancing it.) The rest of the tools should
be fairly easy to set up, and instructions for their installation will
not be provided in the tutorial.
Installing Sappy
Sappy is one of the key programs used when editing music and sounds in a
GBA ROM. When installed properly, it is a fairly good program (though
it has a tendency to crash when encountering anything it doesn't
expect).
Two steps are needed to install the most recent version. Start by installing
version 12,
provided by WaHack. The installer for version 12 will set up some key
system resources that Sappy needs in order to run. When that installer
finishes, run
Sappy version 15.
Sappy 15, unlike previous versions, is compatible with Windows Vista and
Windows 7. It apparently has received some other enhancements as well.
With it set up, you should have no problem viewing GBA music inside of
ROMs.
(We will be using Sappy 15 to preview music and to edit the instruments
that are heard in music, but we will not use it for actual music
insertion. We're doing that manually.)
Finding the song table
The "song table" is a data structure inside of Pokemon FireRed. It is a
list of pointers to all songs and nearly all sounds in the ROM.
Unfortunately for us, it is sandwiched directly between other parts of
the ROM's code; we can't make it bigger without overwriting important
data. We therefore have to repoint it -- that is, move it to a different
location, and tell the game where we moved it. And to repoint it, we
have to find it.
Open your ROM in Sappy. If you are asked to search for a song table, do so.
You should see this:
Closing that dialogue will result in this:
As you can see, Sappy has loaded the song table. We are currently
looking at Song 1, which (if I recall correctly) is played when using a
healing item on a Pokemon. In the lower-left corner, there is a box
labeled "Information". (It may be collapsed; click the chevron to expand
it.) Inside of this box is information on the ROM, including the key
thing we're looking for: the offset of the song table. In my screenshot,
that offset is 0x04A32CC, though it could vary across FireRed versions.
Write that offset down. Close Sappy. Open your ROM in your hex editor, and go to that offset.
Without selecting anything, scroll down until you see eight consecutive
00 bytes. I've marked them with a red line in the image below:
Hold Shift and click directly after the eighth 00. This will select the entire song table.
Paste the song table's hex data into Notepad.
Repointing the song table
Now that we have copied the song table, we need to find free space for it.
At minimum,
you will need to reserve the same amount of space that the song table
occupied originally. However, you'll want to reserve additional space
for new song entries. (If you're not making the table longer, then
there's no reason to repoint it!)
Each song entry is eight bytes: a four-byte pointer, followed by four
bytes of some kind of metadata. So you can either pick an arbitrary
number, or calculate a specific one (a multiple of 8). You can use Free
Space Finder to find enough free space, or you can pick an offset that
you know isn't used (something after 0x800000 that you haven't stored
any data in.)
Scroll to the offset that you have chosen. I am performing this tutorial
using an unaltered FireRed ROM, so I will store the song table right at
0x800000. Click at the starting byte of that offset.
Do a
paste write, not a paste insert. A paste
insert will make your ROM longer, corrupting it. A paste write will
overwrite bytes. Here is my ROM after paste-writing the song table into
its new offset:
Now that we've created a new copy of the song table, we have to tell the
game to use it. Scroll to the top of the ROM. Now, remember the old
offset of the song table? You need to convert it to a pointer. Split the
number into bytes:
4A32CC -> 4A 32 CC
Reverse the order of those bytes:
CC 32 4A
Add an 08 onto the end:
CC 32 4A 08
This is the pointer to the old song table. We need to do the same conversion with the new song table's offset.
800000 -> 80 00 00 -> 00 00 80 08
Now, starting from the beginning of the ROM, search for the old song
table pointer. There are five copies of it, which all need to be
replaced with the pointer to the new song table.
Important note: Some users have reported that their ROMs become
corrupted depending on the order in which the five pointers are changed.
I recommend backing up your ROM before changing the pointers. If you
experience problems, try changing them again and change the first pointer after changing the other four.
The song table should now be repointed. Open your ROM in VBA and test to
make sure. If you get past the title screen, then it works. If it
freezes or crashes, then something went wrong.
If it does work, then you can feel free to replace the old song table with free space bytes (FF), as it is no longer needed.
Extending the song table
Extending the new song table is easy enough. All you have to do is add
more null entries (eight 00 bytes) to the end. Here, I've extended my
table all the way up to, but not including, 0x801000, giving me room for
164 new song entries.
Note that the length of the table doesn't determine how many songs you can
have. It only determines how many songs you can
list. The number of songs you can add is limited by the amount of free space to store song data in.
Telling Sappy where to find the new song table
There is one last thing we have to do before we can actually add music:
we have to tell Sappy where the new song table is. Sappy still thinks
that it's at the old location; we need to change its mind, by editing
its configuration file.
Editing Sappy's configuration file will allow Sappy to open our hacked
ROM, but it will prevent Sappy from opening FireRed ROMs that use the
normal song table. Because of this, we need to create two copies of the
configuration file: one for normal FireRed ROMs, and one for our hacked
ROM. We can switch between the two configuration files depending on what
ROM we are opening in Sappy.
Go to Sappy's folder and create two copies of "sappy.xml". Name the
first "sappy.xml.old", and the second "sappy.xml.hax". Open
"sappy.xml.hax". You should see this:
Find the offset of the old song table, and change it to the new offset. Save.
Now, delete "sappy.xml". Copy "sappy.xml.hax", and rename the copy to
"sappy.xml". Sappy is now prepared to open your hacked ROM. To test it,
use Sappy to open the ROM with the repointed song table. If Sappy can
load that ROM and play songs and sounds from it without crashing, then
it worked.
Preparing a MIDI
Next, we have to actually find some music to import. The music must be
in the MIDI format, so chances are, you won't be able to use something
that's in WAV, MP3, or other normal formats.
VGMusic is a good
place to find MIDI versions of popular video game songs. For this
tutorial, we will be using their MIDI for the song "Bramble Blast", from
Super Smash Bros. Brawl. That MIDI is listed on
this page.
We need to use Anvil Studio to edit that MIDI and make it suitable for
inclusion in the GBA. Specifically, we need to reduce the number of
instrument "tracks" in the song. Download the MIDI, create a copy of it,
and then open that copy in Anvil Studio.
You'll notice that the song has 13 tracks. We need to remove three. If
you maximize the Anvil Studio window, you'll see a panel on the right
side, which shows a large amount of tick marks. Each row of that panel
is like a miniature piece of sheet music, showing the music notes in
each channel.
You'll notice that two tracks have very few notes in the song: "Rev.
Cymbal" and an unnamed track whose instrument is "Celesta". Right-click
on those tracks and delete them from the song. We're down to eleven
tracks now.
A close look at the panels reveal that two tracks have the same musical
instrument. Tracks 9 and 10 both use "SynthStrings 1". The only
differences between them are the notes they play, their volumes, and
their "L/R" (how much audio goes to each speaker).
In this case, Track 9 has an "L/R" of 0, meaning that it is balanced
between both speakers. It also has the higher volume of the two tracks.
So we are going to combine the tracks, keeping the settings in Track 9.
Select Track 9, by clicking in the empty column to its left. In the menus, go to Track -> Merge...
Anvil Studio will show a dialog box asking which track you want to
combine with the selected track. Choose Track 10, and keep the checkbox
checked. Click OK.
You'll see that the tick marks from Track 10 were copied into, and
combined with, those of Track 9. Delete Track 10; it is no longer
needed.
The MIDI is now down to ten tracks. Save the file.
Fixing looping
Real quick: you will need to use Anvil Studio's Compose mode to pad each
track to the same length. Otherwise, some tracks will desynchronize
with each other when the song loops.
Basically, go to View -> Compose. You'll be able to view each track as sheet music. Find the longest track, and edit every
other track. Add rests to the end of those tracks, so that they are all as long as the longest track.
Save the file. Exit.
Converting the MIDI
Here is where Mid2AGB and its component programs become necessary.
Take your modified MIDI file and go to the Mid2AGB folder. Paste the
MIDI into the "mid" folder. In the Mid2AGB folder, open TR.EXE. Click
the "??" button.
If all goes well, you should see your MIDI file listed in the left
column. If it is listed in the right column, then there was something
wrong with it, and Mid2AGB was not able to convert it.
Check the Mid2AGB folder again. There should be a new file: song.gba.
Open this file in an emulator; you will see the name of your song file,
and a person's face in the background. If you press A (or rather, the
key that you mapped the A button to), your MIDI will begin to play. The
song has now been converted! We just need to transfer it from song.gba
into your FireRed ROM.
Open song.gba in your hex editor. Copy all of the data from 0x1B3BB8 to
the end of the file; this is the track data. Create a new file (Ctrl+N),
and paste the copied data into it. (Your hex editor may warn you that
pasting that data will change the size of the new file. Do it anyway.)
Save this file using any name you like.
(The file you are saving contains the track data for the song.)
Use a find-and-replace function to replace all B1 bytes with "B2 00 00
00 00 B1 00 00 00". This is not the usual paste-write, it is a
paste-insert. You actually
want to change the filesize this
time (which is why we copied the information into a separate file). Your
hex editor should perform as many replacements as there are tracks in
the MIDI.
Finally, go to the end of the file. Delete the ASCII text that shows the
original name of your MIDI file, and also delete the four bytes that
come immediately before that text. Save the new file.
Transferring the converted song
Once the track data has been altered, copy the contents of the new file.
Find some free space in your ROM for the track data. In your hex
editor, go to that free space and do a paste-write,
not a paste-insert. (In my ROM, I will be pasting to the offset 0x801000.) Write down the offset that you're starting the paste at.
Note that the free space offset should end in 0, 4, 8, or C. Otherwise, the song header (explained later) won't be readable.
Correcting the track pointers
Before we continue, I'll briefly explain what it is we are about to do.
The data that you have copied into your ROM is track data, followed by a
song header. Each track starts with a BC byte, which marks the start of
the track. The music data follows. After that is a B2 byte and a
four-byte pointer. The B2 acts like a musical "goto" statement, and the
pointer after it is supposed to point back to the start of the track.
Basically, this is the code that makes the track loop.
Unfortunately, our B2 bytes don't have valid pointers after them;
they're followed by 00 00 00 00. We need to change those bytes to point
to the next track, and we need to do this for each track.
Go back to the start of the track data; you should find yourself at a BC
byte. In your hex editor, search for B2. You should find B2 00 00 00 00
B1 00 00 00. The first four 00s are a pointer. Change that pointer to
point to the start of the track.
Search for the next BC byte; this is the start of the second track.
Write down its offset. Search for the next B2; this is the loop code of
the second track. Change the four 00s after it into a pointer to the
second track's BC byte.
Repeat the process for each track in the song, until there are no more
BC bytes. Do not, at any point, lose the offsets to each track; keep all
tracks' offsets written down somewhere.
Correcting the header
After the last B1 00 00 00, you'll find yourself at the header. (Write
down its offset.) The first byte will be the number of tracks in the
song; it will be followed by 00 0A 00. Next is a pointer to the
voicegroup. After that are pointers to each track. Replace each of the
track pointers with the pointers you wrote down earlier.
Now, we will deal with the voicegroup. A voicegroup is a set of
instruments stored in a ROM. Basically, it controls how each track
sounds. We will want to pick a voicegroup from the game to test with.
There is
a list of all voicegroups in FireRed; choose one that has, at minimum, as many instruments as your song has tracks. Copy its offset.
Convert that offset to pointer form. Go back to your song's header, and
change the voicegroup pointer to the new pointer you've chosen. (The
voicegroup pointer came immediately after the first four bytes of the
header, remember?)
Adding the song to the song table
Go back to the repointed song table. Scroll to the last valid entry.
Each entry is a pointer followed by four 00 bytes. Click after the last
entry. Type in a pointer to your new song's header offset.
Save the ROM and open it in Sappy. Go to the song you just inserted, and
attempt to play it. If all goes well, you will hear a recognizable
sequence of notes. The song itself won't sound good at all, because it's
using the wrong instruments at the wrong volumes; however, it's still
playable by Sappy, and the notes themselves have the right timing and
sequence.
In other words, the track data was imported successfully. We now need to change the voicegroup data.
Creating a new voicegroup
A "voicegroup" is a table that lists "voices", or instruments in a GBA
song. Chances are, there won't be a voicegroup in the game that matches
exactly with our imported song. We therefore need to create our own.
Open your ROM in Sappy and go to your new song.
Next to the play and stop buttons, the offset for the voicegroup
(labeled "Voices") will be listed. Double-click it. You will be prompted
to enter the address for a new "voice table".
You will need to find 1536 bytes of free space in your ROM -- room for a
voice table that contains 128 voices, with 12 bytes per voice. Find the
free space, and enter the offset into Sappy. I'll be using 900000 for
this tutorial. Click "OK". If asked if you are sure, click "OK" again.
Because there is no voice data at our new voicegroup, you won't be able
to preview the song anymore; all you'll hear is silence. We're going to
fix that.
Go
here
to see a list of all of the normal voicegroups and their voices. Find
an instrument that you'd like to start with. For the tutorial, we are
going to start with the "Strings" instrument found in the 0x48ABB0
voicegroup.
You'll need to find a song in Sappy that uses that voicegroup. In this
case, song 259 -- a fanfare from RSE. Go to that song in Sappy. Then, go
to Tasks -> Edit voice table.
In Magnius' voicegroup list, each voice had a number next to it. That is
the position of the voice within the voicegroup. The number for
"Strings" was 48, so select voice 48 in the dialog.
Write down
all of the information for that voice. Close the dialog. Go back to the new song that you inserted.
In the screenshot above, I circled a small arrow in red. Click that arrow. Doing so will show you information about each track.
You'll notice that each track has five colored numbers beneath it. The
red number shows what voice the track is currently using. (Yes,
"currently" -- a track can switch from one voice to another mid-song.) I
think the orange number shows the current volume of the track. I have
no idea what the rest of the numbers mean.
Click play, and wait for the song to start. Then, click stop. Now, the
numbers will have values, and you will be able to see which voices each
track is using.
Go to Tasks -> Edit voice table. For each of the voice numbers that
the tracks use, change all properties to make them identical to the
"Strings" voice from the normal voicegroup that we examined earlier.
Now, here is where things will get difficult. You will need to preview
your song, and pay careful attention to the way the individual tracks
sound. For each track, you will need to find the most fitting instrument
in another voicegroup, and change that track's voice to match that
instrument. (For example, I changed voice 25 to the "Electric Bass
(Fingered)" voice from voicegroup 48B8B8.) This will take a while,
because it is largely a trial-and-error process; you'll have to try
copying voices from several voicegroups and finding the one that fits
the best.
When you've found the voices you need and added them to the new
voicegroup, the end result should sound quite a bit like the original
Bramble Blast theme.
But some tracks are missing notes! And some don't play anything at all, no matter what voice I gave them!
I know. I had this problem when coming up with the tutorial.
Basically, there are two major kinds of voices: DirectSound and GBSynth
voices. You can't have more than five of either kind, and you can't have
more than six voices playing at one time if DirectSound is involved.
A GBSynth is any voice that uses a waveform -- that is, Square1,
Square2, Wave, and Noise voices. All other voices (DirectSound and Multi
Sample) are DirectSound.
So when copying voices from the game's normal voicegroups to your new
voicegroup, you have to choose them very carefully. You have to choose a
set of voices based on which tracks use them, and when, so that you
adhere to the above limits.
Oh, and chords? When multiple notes play at the same time? Each note
counts individually toward the DirectSound limit. A six-note chord
counts as six DirectSound instruments playing at once.
As I said -- music hacking is very, very difficult.
Acknowledgements
Information on repointing the song table came
from linkandzelda's tutorial on the subject.
Information on song data structures came
from gamesharkhacker. Additional information on song data structures, along with information on converting and copying song data, came from
the Fire Emblem Ultimate Tutorial [offsite link] (section: "Part 11: The Music Hacking Run-Down").
The Sappy 15 download link came
from ArchsageX. Information on getting it to work came
from Lyzo.
Information on the limits regarding how many DirectSound/MultiSample tracks can play at once came from
this thread by Magnius.
One of the links in the tutorial goes to
a list of all FireRed voicegroups and their voices. That list was compiled by Magnius.
Appendix / Further Reading
A voicegroup has 128 voices (which are zero-indexed in editors) and uses the following syntax:
<voice 0> <voice 1> [...] <voice 127>
Each <voice> represents, well, a voice. Voice definitions are
always 12 bytes long, but their contents vary depending on their type.
(There are five voice types, so far as I am aware.) The format of those
types is not something you
need to know, as voices are generally alterable in Sappy. However, if you are interested in their format, you can check
Charon's New and Improved Music Hacking Tutorials [offsite link].
A thread on the Pokemblem Forums has instructions for transferring voices from voicegroup to voicegroup using a hex editor.
Track data has no padding before or after it, so far as I am aware. 0xBC
marks the start of a track. B2 ZZ YY XX WW is an instruction that tells
the interpreter (the GBA) to jump to offset 0xWWXXYYZZ and continue
playing from there; it is used to loop tracks by jumping back to their
BC bytes.
Song headers are of the following format:
TT 00 0A 00 WW WW WW WW XX XX XX XX[ YY YY YY YY[...]]
Where TT is a byte holding the number of tracks; WWWWWWWW is a pointer
to the voicegroup that the song uses; XXXXXXXX, YYYYYYYY, and so forth
are pointers to the starts of each track (to their BC bytes). So far as I
am aware, there is no padding of any kind before or after the header.
Information on the track data itself can be found
here.
That document contains detailed information on the Sappy format,
including listings of which hex bytes trigger which functions during
audio playback. (Note to self: check if B3 can only be used to jump to
measures rather than independent notes...)