Track Music SpeedUp on Final Lap [Melg, MrBean, CLF78]
#1
This code replaces the usual transition to the fast lap BRSTM (*_f.brstm) by a SpeedUp of the version over 5s. This is especially great for people who use long soundtracks as their custom music and do not get to hear it all in most normal races. The final lap jingle still plays, but the music does not cut and keeps going. Please note that this only affects track music and all other sounds are kept unchanged.
The code is always enabled by default, but you can disable it on select BRSTMs. The code achieves that by editing MrBean35000vr's "Use Byte 0x3F as the volume setting" code and also loading and storing the byte at 0x3E (which is padding).

Instructions:
-If you want your music to speed up on final lap, you just have to add the codes
-For BRSTMs of tracks which you want to behave as per usual, you need to edit the byte at 0x3E of the _n.brstm version and change to exactly 01
This code also effectively means that you do not need to include the _F version of the BRSTMs in your MyStuff/ISO as they are never used.
If you want all your soundtracks to speed up, then you can remove everything starting at the third C2.

Code:
NTSC-U
C2704914 00000012
2C9F0001 41860084
3C80809C 80848F68
88840B8D 7C84F840
40A60070 80850014
38840004 8063003C
38BFFFFE 1CA5000C
7CA32A14 3861FFF6
3D808084 618C23FC
7D8903A6 4E800421
3861FFF6 A0830004
2C840000 41850034
88830006 2C840005
41A50028 807D005C
80630034 80630004
8883FF8E 2C840001
41860010 8083FF4C
3884068D 9083FF4C
881D00DB 00000000
04704930 4186002c
C2704940 00000002
388000DA 40A20008
38800074 00000000
C20a52B0 00000008
80610074 881D003F
2C000000 41A20020
901D0044 3800007F
901D0048 E03D4044
10410CE0 EC211024
D023FFA4 807E0000
881D003E 9803FF8E
807E0000 00000000

PAL
C270B2b8 00000012
2C9F0001 41860084
3C80809C 8084D728
88840B8D 7C84F840
40A60070 80850014
38840004 8063003C
38BFFFFE 1CA5000C
7CA32A14 3861FFF6
3D80807E 618CE860
7D8903A6 4E800421
3861FFF6 A0830004
2C840000 41850034
88830006 2C840005
41A50028 807D005C
80630034 80630004
8883FF8E 2C840001
41860010 8083FF4C
3884068D 9083FF4C
881D00DB 00000000
0470B2D4 4186002c
C270b2e4 00000002
388000DA 40A20008
38800074 00000000
C20a5350 00000008
80610074 881D003F
2C000000 41A20020
901D0044 3800007F
901D0048 E03D4044
10410CE0 EC211024
D023FFA4 807E0000
881D003E 9803FF8E
807E0000 00000000

NTSC-J
C270a924 00000012
2C9F0001 41860084
3C80809C 8084C788
88840B8D 7C84F840
40A60070 80850014
38840004 8063003C
38BFFFFE 1CA5000C
7CA32A14 3861FFF6
3D80807E 618CDECC
7D8903A6 4E800421
3861FFF6 A0830004
2C840000 41850034
88830006 2C840005
41A50028 807D005C
80630034 80630004
8883FF8E 2C840001
41860010 8083FF4C
3884068D 9083FF4C
881D00DB 00000000
0470A940 4186002c
C270A950 00000002
388000DA 40A20008
38800074 00000000
C20a5270 00000008
80610074 881D003F
2C000000 41A20020
901D0044 3800007F
901D0048 E03D4044
10410CE0 EC211024
D023FFA4 807E0000
881D003E 9803FF8E
807E0000 00000000

NTSC-K
C26f9660 00000012
2C9F0001 41860084
3C80809B 8084BD68
88840B8D 7C84F840
40A60070 80850014
38840004 8063003C
38BFFFFE 1CA5000C
7CA32A14 3861FFF6
3D80807D 618CCC20
7D8903A6 4E800421
3861FFF6 A0830004
2C840000 41850034
88830006 2C840005
41A50028 807D005C
80630034 80630004
8883FF8E 2C840001
41860010 8083FF4C
3884068D 9083FF4C
881D00DB 00000000
046F967C 4186002c
C26F968C 00000002
388000DA 40A20008
38800074 00000000
C20a53B0 00000008
80610074 881D003F
2C000000 41A20020
901D0044 3800007F
901D0048 E03D4044
10410CE0 EC211024
D023FFA4 807E0000
881D003E 9803FF8E
807E0000 00000000

SOURCE:
Code:
First ASM: Check if the conditions (lap, timer, flag) are met and then executes the speedup
#inject(0x8070B2b8)\n\n (PAL)
#inject(0x80704914)\n\n (NTSC-U)
#inject(0x8070a924)\n\n (NTSC-J)
#inject(0x806f9660)\n\n (NTSC-K)

.set region, 'P'
.if (region == 'P' || region == 'p') # RMCP

.set RACEINFO, 0x809BD730
.set RACEDATA, 0x809bd728
.set SOUNDDATA, 0x809C2898
.set SubtractTimers, 0x807ee860

.elseif (region == 'E' || region == 'e') # RMCE
.set RACEDATA, 0x809B8F68
.set SubtractTimers, 0x808423FC

.elseif (region == 'J' || region == 'j') # RMCJ
.set RACEDATA, 0x809BC788
.set SubtractTimers, 0x807EDECC

.elseif (region == 'K' || region == 'k') # RMCk
.set RACEDATA, 0x809abd68
.set SubtractTimers, 0x807DCC20

.else # Invalid Region
.abort
.endif

#r3 = RaceInfoPlayer[LocalPlayer0], r5 = RACEINFO, r29 = PlayerHolder->PlayerArray[LocalPlayer0 ID]->PlayerPointers->Field 0x1C, r31 = MaxLap of LocalPlayer0

#cr1 = CR bit used later in the function to swap (or not) to the _F version of the brstm

cmpwi cr1, r31, 1    #Check if currentLap>1 (if it's first lap then no laps have been stored in RaceInfo)
beq- cr1, end

lis r4, RACEDATA@ha
lwz r4, RACEDATA@l (r4)
lbz r4, 0xb8d (r4) #LapCount
cmplw cr1, r4, r31 #If MaxLap = LapCount, we are on final lap
bne+ cr1, end

lwz r4, 0x14 (r5)  #RaceInfo->TimerManager
addi r4, r4, 0x4   #Align with the minutes

lwz r3, 0x3C (r3)  #RaceInfoPlayer[Me]->lapFinishTimes Array
subi r5, r31, 2    #First position of that array gets stored on the transition from lap 1 to 2 (ie MaxLap = 2=
mulli r5, r5, 0xC  #Each array element is 0xC long

add r5, r3, r5     #Get the correct array element depending on the lap

subi r3, sp, 10    #Buffer for the function

lis r12, SubtractTimers@h      #Calculates the time elapsed since the player last crossed the line
ori r12, r12, SubtractTimers@l
mtctr r12
bctrl

subi r3, sp, 10
lhz r4, 0x4 (r3)  #Minutes elapsed
cmpwi cr1, r4, 0  #End if 1m or more
bgt- cr1, end

lbz r4, 0x6 (r3)  #Seconds elapsed
cmpwi cr1, r4, 5  #Only execute the speedup for the first 5s
bgt+ cr1, end



lwz r3, 0x5C (r29) #0x809C2898 -> Field 0x5BC which gets stored when PlayerHolder gets constructed on loading.
lwz r3, 0x34 (r3)
lwz r3, 0x4 (r3)

lbz r4, -0x72 (r3) #SpeedupFlag, initially byte 0x3E of the BRSTM
cmpwi cr1, r4, 1   #If it's 1, skip the speedup
beq- cr1, end
lwz r4, -0xB4 (r3)
addi r4, r4, 0x68D #Additive speedup
stw r4, -0xB4 (r3)

end:
lbz r0, 0xDB (r29) #Default

------------------------------------------------------------------------------------
Followed a few instructions later by beq- cr1, 0x2c (the 04 in the code). The game has already checked that we are on a lap transition. If the branch is taken, then normal behaviour will occur.
Code:
Second ASM: in the same function as the first ASM. 

#inject(0x8070b2e4)\n\n (PAL)
#inject(0x80704940)\n\n (NTSC-U)
#inject(0x8070A950)\n\n (NTSC-J)
#inject(0x806F968C)\n\n (NTSC-K)

#Changes the BRSAR sound ID arg that the game will use for the lap jingle. Before this ASM, there is a "compare current lap with lap count", hence the bne+
li r4, 0xda  #If on final lap, play the normal lap jingle
bne+ end
li r4, 0x74  #Else, play the normal lap jingle
end:

Code:
Third ASM: Keeps the volume part from MrBean's initial code, and now also load and store byte 0x3E
#inject(0x800a5350)\n\n (PAL)
#inject(0x800a52B0)\n\n (NTSC-U)
#inject(0x800a5270)\n\n (NTSC-J)
#inject(0x800a53B0)\n\n (NTSC-K)

#The game has already checked that it has correctly loaded the BRSTM Header.

#r29 points to the BRSTM header
lwz r3, 0x74(sp)            #Pointer to a structure where a bunch of music related settings are stored, including volume and speed
lbz r0, 0x3F(r29)           #Get the volume byte

cmpwi r0, 0                 #If the byte hasn't been changed, return
beq+ end

stw r0, 0x44(r29)           #Store values in the stack, free space as BRSTM headers are only 0x40 bytes
li r0, 0x7F
stw r0, 0x48(r29)

psq_l f1, 0x44(r29), 0, 4  #Reload floats using paired singles
ps_merge11 f2, f1, f1      #Move f1 ps1 to f2
fdivs f1, f1, f2
stfs f1, -0x5C(r3)


end:
lwz r3, 0(r30)             #Original instruction default
lbz r0, 0x3E (r29)
stb r0, -0x72 (r3)
lwz r3, 0 (r30)       #Default


Code Creator: Melg (first and second ASM, modifications of the third ASM to add a second flag), MrBean (third ASM), CLF78 (suggested using paired singles for the float conversion then wrote a better code than me, also gave the initial idea for the code https://mariokartwii.com/showthread.php?tid=1648)
Reply
#2
Tested PAL and NTSC-U versions and they work like a charm! An Excellent way to make your distribution more compact should you strive to contain an overflowing amount of tracks.

Just a small question. Would it be possible to alter the code to change the percentage the music would speed up on the final lap? If so, how?
Reply
#3
(06-08-2022, 07:53 PM)Mr. Archives Wrote: Tested PAL and NTSC-U versions and they work like a charm! An Excellent way to make your distribution more compact should you strive to contain an overflowing amount of tracks.

Just a small question. Would it be possible to alter the code to change the percentage the music would speed up on the final lap? If so, how?

That's possible yeah, change the 3884068D to 3884XXXX, where XXX is ultimately equal to how much the music speeds up each frame. A higher value than 68D will lead to a faster increase, and a lower will do the opposite.

To get more technical, since adding floats constants isn't practical in ASM, I use a small trick to do that more efficiently.
The speedup occurs over 5s, which is 300 frames. 0x68D * 0x12C (300 in hex) is equal to 0x7AD3C. It so happens that 3F87AD3C is 1.06 in float, so the total increase is 6%.
You can use this website https://babbage.cs.qc.cuny.edu/IEEE-754....cimal.html, convert the final increase you want (for example 1.04), remove the 3F8, divide by 0x12C and that'll be your XXXX. 

If you're not familiar with these concepts, just try some values (0x45E will lead to a 4% increase roughly to get an order of magnitude).
Reply
#4
I've been playing around with this code and so far I'm enjoying it a lot, the cut-off and how the music pretty much restarts from the beginning to changing something like what this code does is quite a game-changer, great job! Especially when combining it with the Track Music Expander code, it saves a lot of space for custom tracks.

However, there's only one downside with the code currently and that it only works for races; battle mode seems to load the regular final-minute music. There are two battle mode mods where there are extra cups and stages added to the game, if the code could be updated so that it works for battle mode as well (haven't tried Mission mode with it at the time I posted this message), then I'm sure many more users will make good use of this one. Smile
Reply
#5
I really like this gecko code, however it does bother me that the final lap jingle plays over the top of the music, that the music sort of weirdly cuts out when everyone has finished and not when you finish, and that the music keeps getting higher and higher when more people enter lap 3 in multiplayer. Is there any chance of a version of this code which doesn’t do the gradual speed up and simply plays the music a semitone higher when the first player enters lap 3? It could start from the beginning or ‘pick up where it left off’. It would also be nice if the music didn’t keep going after you finish before an ‘awkward silence’ then the finish music plays (?). Thanks!
Reply


Forum Jump:


Users browsing this thread: 2 Guest(s)