Adding Songs to FireRed: A Dreadful Tutorial
View Single Post
August 4th, 2011, 08:39 PM
Join Date: Jul 2010
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.
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
way. But it's
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
out of it. So there's that.
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...
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.
A hex editor, such as HxD
Free Space Finder (FSF)
Sappy, mod 15
Anvil Studio 2011
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.
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
, 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.
, 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.
, 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
. It only determines how many songs you can
. 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.
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
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.
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
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
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,
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.
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.
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.
Information on repointing the song table came
from linkandzelda's tutorial
on the subject.
Information on song data structures came
. 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
. Information on getting it to work came
Information on the limits regarding how many DirectSound/MultiSample tracks can play at once came from
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
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
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
. 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...)
PokeMart as debug input
script compilation at runtime
music: a dreadful tutorial
I'm not active and don't do this kind of stuff anymore. I'm now trying to create my own game engine.
two message boxes at once
[WIP] firered RAM map
list of all known flags/vars in firered
script command ref: 114 complete / 175 documented / 214
Last edited by DavidJCobb; August 10th, 2011 at
. Reason: Chords.
View Public Profile
Send a private message to DavidJCobb
Find all posts by DavidJCobb
Find threads started by DavidJCobb
Ignore Posts by DavidJCobb