Well, after my last blog entry about the sound test in gimmick, I remembered that in the sound test of batman return of the joker I did notice one bit of music clearly missing and while I wanted to look as to why I just didnt for some reason, until now. The sound test is pretty easily accessible by just pressing a+start on the title screen, leading you to this screen:
As you can see, it starts on A and for the music goes up to M and for the sound effects up to Z.Warning: Spoilers inside!
Also I had a look on tcrf again and saw this little bit:
"Track 6 in the NSF file is not present in the sound test. The fact it loops suggests it might have been intended for a stage."
So I was right in thinking that something was missing here.
I tried looking in a hex editor if I could find a string like "SOUND TEST" in it, but did not find anything so yet again, it was time to fire up the emulator and check out whats going on!
This was about as simple as it gets, right in the beginning of RAM it was very obvious what byte is used to represent the currently selected bit of music:
See how when I select BGM A on the bottom the marked memory value is 00, and when I select BGM B its 01, well that just continues to count up when I go up further. All I had to do is set a write breakpoint to find what piece of code is responsible for increasing that value:Warning: Spoilers inside!
All that does is increase that position and if it finds out that position in address 0x11 is larger or equal to 0xD (N), it will loop back down to 0 (A). Also that bit of code above includes the same type of checks for the sound effects position in address 0x12 not going higher than Z, as well as when you want to go below A with the BGM, it will go back up to M, and with the sound effects go back up to Z. Next up I had to figure out how high those values really should go, because I had a feeling theres more sound effects than up to the letter "Z" and maybe even more BGM too, which was just a quick check of what reads from the music position at 0x11 when I press "A" to start playing that bit of music.
Ah yes, there is a list of actual music values involved of course at address 9C85, so it takes the position from 0x11, then loads whatever the corresponding music value is from that list, and stores that value into 0x41. Oh and for the sound effects that bit of code was again right above this, where it gets the position from 0x12, loads the sound effect value from a list at address 9C92 and stores that value into 0x42. Now it was time to take a look at those lists to see exactly whats going on.
Here is that list for the BGM:
If you know your hexadecimal system you may notice that 0x06 and 0x0E are missing from that list, I had a quick check if those are indeed music tracks by just manually writing 0x06 and 0x0E into address 0x41 as the game would do to start playing music and indeed, 2 music tracks you dont hear in the sound test started to play. So this would be the first set of patches, I replaced the comparison of larger or equal to 0xD (N) with larger or equal to 0xF (P) as well as when going below A it would go back up to O instead of M. Now the nice thing about how music works here is that it actually is not just a random list of values but its just going up by 1 every time, so the only difference from the selected position and the actual music value is that the music value is 1 higher than the position (position 0=music value 1 etc), so I replaced that load from list with it just increasing the position from 0x11 by 1, moving it over to register A where it normally loads the music value and just as a technicality a "nop" instruction, that one does literally nothing, I just had to add that because the original instruction to load the value from list took 3 bytes, but the increase of position and moving it to register A only takes 2 bytes, so that "nop" just acts as a "filler" byte.
Great, now all the music is accessable! Of course I could not stop there, I had to take a look at the sound effect list as well, its right behind the music list, I marked it here:
I noticed that right at the end there is that jump from 0x38 to 0x3B, and if you know your hexadecimal numbers that means at least 0x39 and 0x3A are missing, so I wrote those into address 0x42 and indeed, those are valid sound effects. I then just to see went up higher, so 0x3C, 0x3D... and all the way up to 0x48 there were valid sound effects, meaning that in total even though this is a sound test, a whole 15 sound effects were not selectable from it! Again since the sound effects were all in order and not all over the place, that list again was not needed, I replaced the sound effect load from a list to simply add 0x20 to the sound effect position from 0x12 (so position 0x00=sound effect value 0x20 etc) .
So to make all those sound effects selectable it was just a simple job of patching the effect comparisons up to not stop at Z but go much higher, now you may notice an issue with that, after Z theres not exactly any more letters to go up so while yes, I now could listen to all sound effects, the selection doesnt look all that great...
Ah yes, effect <garbled mess> is my favorite! So I could have just left it there because it was working just fine and it was very little I patched over all, it was just graphically weird to look at, but in the end I decided I wanted to change the select system from A-Z to numbers instead. This of course ended up making this patch quite a bit longer.Warning: Spoilers inside!
So address 0x11 and 0x12 dont just get read for increasing/decreasing and choosing a piece of BGM/sound effect to play, but also from a 3rd bit of code:
This bit of code loads a tile number from a list at address 9C6B based on the music position at address 0x11 (A=tile 0x22 here), stores that in 0x21, then loads the X position where that tile should be on screen (0x9C in this case), stores that in 0x94, then the Y position going to 0x95 and 0x96 and 0x97 are irrelevant here, after that it calls a function at C247, this function basically takes the parameters just saved in those addresses and puts that tile on screen for us. Right below this bit of code is a near identical piece of code that loads from address 0x12 and has a different X and Y position and calls C247 then as well, of course this is for the sound effect tile. My idea now was to replace this tile list of letters with just the tile 0 repeated 10 times, then 1 repeated 10 times, and so on to be the upper digit for this number selection, now finding those number tiles was easy enough:Warning: Spoilers inside!
As you can see I am hovering over the 0 which is value 0x40, 1 is value 0x50 and so on, so I replaced that tile list at 9C6B accordingly:Warning: Spoilers inside!
You may notice, I just wrote right over the music list and sound effect list because at this point they were not used anymore. So now I have the upper digit in place, of course I still need the lower digit, which meant I needed to add some of my own code. Luckily, there is a giant section of memory just unused right below the sound test, so I could just work right into this:Warning: Spoilers inside!
You can see I still marked the sound effect list on top, and from that point its just a whole lot of nothing, and that is not even all of it, it goes further than that even, so lots of space to work with for once. Now time for some custom code! I decided to replace the function call to C247 for both BGM and sound effect with a call to some empty memory at 9E47, and placed this bit of code into that area:Warning: Spoilers inside!
This bit of code first secures the position of BGM/sound effect that called us so we can use this bit of code for both BGM and sound effect in the first place, else we would have to have separate code for loading both positions from 0x11 and 0x12, then it calls C247 to draw the upper digit part, after that it restores that position and loads the lower digit from a separate tile list I've made at 9E5E that just repeats 1,2,3,4,5,6,7,8,9,0 so often that it can cover all 41 different sound effects, we have enough free space after all, it then stores that tile position into address 0x21, adds 8 to the X position at 0x94 of the tile it just drew so we are exactly right of the tile of the upper digit it just drew, and then we call C247 again to draw our new lower digit tile, then we return to whatever BGM/sound effect called us.Warning: Spoilers inside!
With all that, we now replaced the A-Z system with a system that can go from 01-41, now of course its time to give this a shot on real hardware to make sure what I just wrote up all works!
And it is now working as it should, very good!
As always, I of course pushed that patch to my github.
If you are for some reason interested in recordings of the PAL version from my hardware using this patched file, here you go:
I know, these patches are all pretty useless but still, I feel like just sharing the process this goes through so I have a reference for later and to maybe help others understand how things work in a bit more detail. Thanks for reading.
You need to be logged in to comment