In part one, I started a journey to add more music to Persona 3, and to randomly select between new and old tracks.
I left off with a very specific problem when replacing a file: the game is reading the file’s location inside BGM.CVM from something other than the CVM file. The only place I can think of that would have the answer is the source code. A little Googling reveals a program named PS2Dis, a PS2 disassembler. Let’s open the SLUS_216.21 file.
We’re clearly going to need a little background on assembly. The PS2 runs a 64-bit MIPS R5900 processor. I don’t really know what that means, but now I know what instruction set to Google. This overview got me mostly up to speed pretty fast.
Alright, now we have a small chance of understanding what we come across. After exploring the menus of PS2Dis, it seems we can open a label list by pressing Ctrl-G.
Neat! Well, we know the music files are all named “#.ADX”, so let’s try entering “01.ADX” (this is the one time you actually type the quotes).
Hmm, there’s a list of song names, but there’s nothing that looks like a file table with offsets and sizes. What if we Find (Ctrl-F) “01.ADX” instead?
Bingo. (Side note: you can change the data type PS2Dis displays an address with “C” for instruction, “B” for byte, and “W” for word. It greatly enhances readability, as it’ll automatically display ASCII values for bytes and preview the value of words containing addresses.)
Let’s see if we can find the start of this “file table.”
Aha. After some analysis (the output of cvmtool helps a lot), here’s the format:
uint32 file_count uint32 file_count //yes, twice uint32 0x00000014 //magic number! "#DirLst#" uint32 0x00000000 for each file: uint32 file_size uint32 extAttributeLen //still not 100% sure if this is right, but it's always zero, so... uint32 file_offset uint8 flags uint8 unknown //I have no idea what this is. It's nonzero and fluctuates, but just writing 0x00 here works fine. char filename //always 34 bytes, with the unused bytes set to 0x00
Simple enough. Let’s keep investigating – where does the game decide which music file to load? Let’s go back to that first list of song names.
Cool. If we press Space and then F3, we can use PS2Dis’s analysis tool to find code that refers to this address.
Alright, so – wait a second, that “li” does not refer to the address we were just at. Let’s follow it (press the right arrow) and see what it’s loading…
Ah, it’s a list of the addresses of the filenames, evenly spaced by 12 bytes (0x0C). We can test our theory by changing 0x0010920c’s “load immediate” address to be 0x0C bytes further ahead. Try it and, indeed, just about every song in the game will change, because we’ve offset the array index by one.
We’ve now covered how to modify the BGM.CVM file to add or modify music files, and the necessary source code changes that must be made to accomodate the new files. In Part 3, I’ll talk about the tool I wrote to actually change things, as well as the assembly routine for picking songs.