Today I felt like writing a bit about some of the other random stuff I do, if you did not know, a lot of older console titles were very lazily released on PAL consoles which led to them running slower in both audio and video. I dont really mind the slower gameplay itself, but the music part of it is really annoying to me if it was not adjusted, as is the case with megaman 1 and 2. Because I do own a PAL NES living in europe I wanted to see if I could somehow patch my way around at least the music.
This is a full breakdown of what went into making these PAL megaman music patches on my github:
To demonstrate how it is unpatched, have a listen to flash mans stage in megaman 2 as it is supposed to sound from ntsc:
Got that beat still going in your head? Well, let me quickly destroy that with the PAL version of it:
I think now you understand the issue a bit better.
So, I had a quick google around to see if anyone had done some work on it before and while I did not find any existing patches, I did find a incredibly useful disassembly of both megaman 1 and the audio driver of megaman 2:
Having a read through this, I saw that each song has a speed value attached to it:
This value gets used to multiply each notes length to calculate how long it takes between notes, so I thought hey, why dont I change that 6 to a 5, maybe thats enough of a speedup to get closer to ntsc speed, and well, have a listen for yourself:
WOW, for such a simple patch that did exactly what I wanted it to! So I went ahead and applied this method to every song in the game and thought at the time it all sounded correct (spoiler: not every song was correct), now before calling that patch done I did also edit the intro and credits length because the audio did not sync up anymore.
This process basically was just me watching the game RAM to see where a value counted down until another event happened, setting a breakpoint on that RAM value to then reduce the initial value that was written into it by the game so it would take less time to count down, thus speeding up whatever was happening. I did that to many small parts and in case you dont really understand what I just wrote, let me give one direct example of this with a bit of slowed down video, watch how the screen transitions:
You see on the bottom right how those screen transitions happen when both the value I marked and the value next to it hit 0? Those values then get reloaded with a new number, $49 in the spot I marked and $01 in the spot next to it by this bit of code:
That starts counting down again and those numbers are exactly what I edited to take less time to count down, let me give you a very drastic example of very small numbers to see it very clear:
In this one I just forced the value next to the one I marked (framecnt high) to load with 0 to skip a lot of counting, of course in my patch I strategically chose values that let the intro and credits be perfectly synced with the music without anything being skipped on screen, this was just a quick video demonstration of the technique I used
Right, so then I went ahead and released that as v1 of my pal music patch, thinking it was all fine...
and then recently I finally looked at megaman 1 because that uses pretty much the same exact music driver. So in that game as well, there are the exact speed values too that you can edit:
So I again subtracted 1 from that, it sounded great, I went on to do the same for the rest but I noticed that when you select a boss, things start... messing up. Let me demonstrate what you would expect to hear:
...and what I actually heard when I modified the speed value of the boss selected music:
You heard how that ending note just got stuck? Well I did again mark the position in RAM in that video that messed up here, that one took me a bit to figure out, basically what happened with me reducing the speed value here is that the note length suddenly underflowed, meaning it became a very, very large number (FF as you can see) instead of going to 0 as it is supposed to for the next note to load, you see the speed value gets multiplied with the current note length to determine how long it should wait to load the next note. In this particular case the note was a length of 2 and my patched speed value was 5, meaning the calculated wait time was 10. The issue is, every time the music driver processes a note, it subtracts 4 from that wait time, and you see, 10 is not exactly divisible by 4 meaning that it subtracted too much, resulting in the note suddenly becoming a very large number instead of 0:
Of course I went back to megaman 2 to see if it happens there too and yes, it happens on the boss select as well as quick mans stage, but it does not make a note get stuck like that but just silences the channel instead because it actually underflows on a pause command rather than a play note command, thats how I did not even realize something went wrong there.
After thinking a lot about how to tackle this issue in the shortest way possible, I came up with a machine code patch to replace the current logic of subtracting 4 to instead subtract 2, see if its 0, if it is load the next note and subtract 2 from that, and if its not 0, subtract 2 from the current note again. That way I never miss a length subtraction and everything should stay in sync properly.
Now to make an edit like this, I would need to add extra code to the existing one by injecting it into some free space, so I looked at both megaman 1 and 2 to determine the best spot, and at the highest possible spot for code to be added there luckily was some free space in both games:
It may not be a whole lot, but it was worth a try, so now for the entire code bit I wanted to edit after thinking about it:
What this does is first check if the note length is 0, if it is it jumps to the ++ bit at the bottom, if it is not, it will subtract 4 from it, see again if its 0, if it is it jumps to the ++ bit, it then checks the note period (the tone you hear basically), if that is 0 it will exit (on a pause for example), and if it is not 0 it will process the note further (adjust its volume, vibrato, etc).Warning: Spoilers inside!
So I decided to replace the check for it being 0, subtracting and checking if its 0 again with this bit of code:
This now calls a little function "subfunc" I wrote that does checks if its 0, if it is it will return to this code, if it is not, it will subtract 2 and check if its 0 again. After the function returns and it was 0, it will load the next note, then call our little function "subfunc" again and exit out, it does no note processing because that turns out to be buggy at times. If the current note was not 0, it will subtract 2 from it again using "subfunc", if that still was not 0, it will then jump to that bit of code checking for the note period which then processes the note.Warning: Spoilers inside!
What a first patch! Now that is just patch number one of course, this is the "subfunc" function:
As you can see it does exactly what I explained before, check if 0, subtract, check if 0 again. You see that little bit "jump over existing data"? Well you may have seen in the bit of free space I found it was not all 00, but there was something already, that just jumps over that bit. Now if you are wondering how close it was to not fitting, check out this picture of the patch now being in that free space:Warning: Spoilers inside!
Yep, I used every last byte that was available to me, that was indeed a close one!
Now with this patch in place, have a listen to the boss selected music now:
Now thats more like it! With this patch in both megaman 1 and 2, it was pretty much done, so I now finally finished up editing all the songs in megaman 1 and adjust its ending to be in sync with the music using the exact same technique as I did before.
The only thing that I now noticed was off was icemans stage in megaman 1, the volume of some notes was cutting off way too early, have a listen to this:
Those notes should just stay held but they fall off pretty much immediately, this one took me a bit to figure out but basically this particular music command:
Sets the length of the volume curve ($86) and the strength ($20) of which it should fall down. Now only in this particular song it seems to fall off in such a way that it gets reset right when the length hits 0, you see when it hits that 0 length in the song itself it actually immediately reloads the next note, meaning the volume never gets decreased because it gets reset at the same time.
But now that we have a different play speed, this does not occur because the volume only gets reset if that length is 0, and the note reloads at a different point now, meaning it does not reload the volume and it never recovers the loss in volume. Since this is the only song to have this issue from what I've heard, I decided to just modify the length of the volume curve in this song alone in such a way that it plays back as close to the intended audio as possible. And while I did not get it 100% perfect for every note, it is good enough to me, have a listen to that part again that before cut off after modifying the volume curve length:
Now it does not cut off early anymore! So while probably not the prettiest solution it did work out well enough for something that was never intended to be played at PAL speed I think.
So there we have it, now you know how much work patching just a few bytes can be, if you want to give these patches for PAL megaman 1 and 2 a try, again there are up on my github of course in case you did not see the link in the beginning of this blog entry
Even if you have no interest in PAL things I hope this was still an interesting read to you about the process of patching a couple of bytes in something as simple as NES titles, thanks for reading.
You need to be logged in to comment