Recently I wondered if the nes game gimmick! has a sound test to listen to its excellent music so I did a quick search and yes, it actually does as is described on tcrf:
Just hold down select and start on the title, simple enough.
Now while that was all well and good, this particular sentence on tcrf immediately made me consider making a patch:Warning: Spoilers inside!
"It contains every track in the game, with the exception of Evidence of My Life (later named in a separate OST) and an alternate version of Cadbury with slightly different instruments."
In this blog entry, I will write down what I had to do to make a patch like this.
While those 2 tracks arent exactly long or special, it still seems weird to me as to why they would not be accessible in the games own sound test, so it was time to fire up a hex editor and see where that text is located, maybe it was just deactivated or something. Well, after a quick search we find this:
If you compare that text to the right with the ones on the previous image, you can see that this is indeed what we were looking for, but no mention of those 2 tracks are in there so the sound test seems to just not include them. Also if you are wondering why there are seemingly random symbols in between the readable text, this is not just pure text but contains some extra information as well, we will get to that. Well now it was time to fire up an emulator and see where this set of characters gets read from to see what we can do, here I set a breakpoint on when the "M" of "MUSIC" gets read:Warning: Spoilers inside!
This function may contain quite a few instructions but its job is very simple, it gets an address handed over that it has to then copy into video ram, and the extra data in between that readable text was the address it gets copied to (like the 2 bytes before "MUSIC", 20 89), as well as a spacer (FF after "SAMPLER" for example) to tell it when its done copying into that destination address, and 2 bytes as an end point where to stop copying (FF FF). Time to step out of this function and see what called us then!Warning: Spoilers inside!
So it stores the first part of the address into 00 and the second part into 01 and then calls that copy function, and for some reason, it does so twice, once for the first half of text (see the FF FF in the hex editor in the middle of the 00037ED8 line?) and then for the second half right after, hm, thats a bit of a waste of code. This will actually turn out to be a good thingWarning: Spoilers inside!
Now that we know how it copies text over, we have to figure out how it decides which song to play once we press A, this is simple enough, I looked at the RAM when pressing A and saw that address F5 changes to 80, so scrolling down a bit further down that code that set up the text I found this little bit:
Ah yes, this tells us exactly how the music driver works, when it sees we pressed A (address F5 contains 80), it loads the position of the song select cursor into Y (can be 0-17) from address 0F, it then grabs the actual song number that is from a small list at 9DD9:Warning: Spoilers inside!
Notice how thats right above the list with the text? That song number gets stored in address 70 and then finally it stores 1 in address 71, which basically tells the music driver to start playing that number. That was easy enough to verify by me just writing in a song number into address 70 by hand and then 1 into address 71 and indeed, it started playing music. That bit of code also compares address F5 to 40, thats when you press B, in that case it stores 2 into address 71, that will stop playing whatever music it was playing, simple enough.Warning: Spoilers inside!
Maybe you already noticed it, but that very first picture contains less song names than are visible in the hex editor, thats because that list can be scrolled down further when you press down, that part is handled by the code right below the one for starting and stopping the music:
So as you can see it grabs the position of the song select cursor again from address 0F into Y, then gets the scroll value it should be at from yet another list at 9DEB:Warning: Spoilers inside!
which as you can see is right between the song list and the text on screen, so now we know the memory is well packed, and after getting that scroll value it should be at it adjusts the current screen scroll to be at that scroll value.Warning: Spoilers inside!
With all that information, we now know enough to think about editing this sound test with 2 extra songs, we will have to add 2 bytes with the missing song number to that list at 9DD9, then we need to add 2 bytes to the scroll list at 9DEB and of course add the new text and addresses to the big text list at 9DFD.
There is of course one problem, all those lists are right next to each other already, with no room in between, so we cant really add anything into that is it is right now... That means, we have to move it around a little to make some more space for all that extra data! Thankfully, right at the end of the memory area used for this sound test, there is actually a little bit of leftover space:
That bit of space is enough to fit in both the bigger list of song numbers and bigger list of scroll values, perfect! Now since I know already how the music driver works finding the 2 missing song numbers was easy, just enter a number manually in RAM and listen, turns out the 2 song numbers are 0A and 2B, which as you can see in the song number list are obviously not there, and the scroll values always go up in 10 steps, so instead of ending on 70 80 80 80... I now let it end on 70 80 90 A0 A0 A0... ending up with this:Warning: Spoilers inside!
With that, the new song number list address is 9FD8 and the new scroll value address is 9FEC, I of course updated the code as well to reflect those changes.Warning: Spoilers inside!
Right, now that we have the lists moved, giving us a whole 36 bytes of space to play with, so now I wrote the new song titles in that format with address, spacer and all that and... the way I wrote it takes 37 bytes...Warning: Spoilers inside!
...which actually, is perfect, remember how earlier I said there was some wasted code with copying the text in 2 sections by having 2 end bytes (FF FF) in there? Well, why dont we just change those 2 end bytes (FF FF) into a spacer instead (FF), edit that first copy address to now be where the song number list was previously, 9DD9, and then jump over the code that does that second copy:
Well then the new song names fit in perfectly, filling out every byte that we have available!Warning: Spoilers inside!
We are almost done with this patch, we now have the 2 missing songs added into the lists and all, but of course, we still have to edit the code that tells us how far we can scroll down, or else we can never actually select the last 2 songs of course, which is just a simple edit of this code:Warning: Spoilers inside!
this just grabs our cursor position from address 0F again, adds 1 to it, if its bigger than 0x12 (18) it wont save that new value, if it is smaller it will save it. So we just have to add 2 to that comparison:Warning: Spoilers inside!
and there we go, now it will let us select all songs again. Now I was pretty much done, but on tcrf there was yet another sentence that I wanted to address:Warning: Spoilers inside!
"The round cursor color depends on bits 1 and 2 (a total of four different colors) of some music data, which don't frequently change and remain at zero most of the time with the exception of two music tracks: Strange Memories of Death and Paradigm. This color change only occurs in the Japanese version."
With that description, it was very simple to find the exact code bit this was talking about by just looking at the RAM and the code:
So it grabs a value from address 0699, and then grabs a color from those 2 small lists at 9DD1 and 9DD5, which you may notice is right below our text:Warning: Spoilers inside!
Just showing that we could not have moved that text up further or it may have done weird things to the cursor, so I looked at address 0699 and saw that indeed, it was really rare to see any change in the japanese version and it never changed in the european version so I just went ahead and edited that bit of code to point to an address that changes far more frequently, 060B:Warning: Spoilers inside!
Now I was happy with that sound test, I know this probably was the most pointless thing I've done in quite a while but hey, thats just what I do, random stuff when I feel like it.Warning: Spoilers inside!
After all those edits I of course made a patch for it and put it up on my github, as always:
Now there was just one last thing left for me, and that is give this a shot on real hardware and see if it all loads up as I would expect and work as intended:
Success! Everything shows up exactly as it should, plays back audio just fine and the cursor now is actually active for once changing color frequently.
If you are for some reason interested in recordings of the PAL version from my hardware using this patched file, here you go:
Thats it for now, as always, interesting how something so simple can get so complicated. Thanks for reading.
You need to be logged in to comment