Fixed Sonic 2 Sound Driver Port to Sonic 1

Discussion in 'Tutorials Archive' started by SuperEgg, Apr 13, 2013.

Thread Status:
Not open for further replies.
  1. SuperEgg

    SuperEgg I'm a guy that knows that you know that I know Member

    Joined:
    Oct 17, 2009
    Messages:
    Location:
    THE BEST GOD DAMN STATE OF TEXAS
    Hey guys, it's SuperEgg here. Now as some of you know, there is already this tutorial up on Sonic Retro, but I've found quite a few issues with the guide. Either it was missing something, or the RAM addresses were over writing each other.

    Earlier today, after talking a bit with vladikcomper about the fixed sound driver I have present in Build-A-Burger, and how it is slightly better than the stock S2F/rev2 driver, I decided to port it into Sonic 1. But as one could have guessed, I didn't like the guide on Retro...at all. To be frank, there were a steps missing, not to mention it was messy. So I've decided to write an alternative in hopes that it can help you people out.

    I would like to note, that a lot of the fixes come from Sonic 2 rev2. Why? Because Revision 2 uses a few different RAM addresses than the Xenowhirl one, thus working better. Along with that, there is no need to add in this asston of equates into the game. It is tiresome and not to mention completely unnecessary. Since there is only a handful of RAM addresses that need to be used, porting the whole constants file is just a waste. Along with it, the RAM addresses that correlate to music and sound, overlap those used for the level select activation RAM addresses. The Revision 2 doesn't have these issues, so that is the reasoning behind my use of it.

    First, here is the files necessary for the driver. Go ahead and download it and place it in the root of the S1 disassembly folder. Don't move any of the files in the folder. 

    https://www.dropbox.com/s/os061fbutgawxf5/Sound%20Driver.zip

    This folder contains.

    - The fixed driver.

    - The fixed z80

    - All the music and sounds.

    Now, since we have the files all squared away, lets start on the actual tutorial, shall we?

    Step One: General Fixes

    As I was working with Sonic 1, I've found lots of things that could be optimized, or fixed that way we don't have to keep going back and forth, trying to fix it. I.e, we're going to make the code efficient.

    First up, Music problem.

    In stock Sonic 1, we see this.


    Level_PlayBgm:
    lea (MusicList).l,a1 ; load music playlist
    move.b (a1,d0.w),d0 ; add d0 to a1
    bsr.w PlaySound ; play music
    move.b #$34,($FFFFD080).w ; load title card object
    That's all fine and dandy. But with this setup, if the music ever changes, it has to be manually set, or has to have a separate playlist to access the music. So, in order to fix it. Replace everything under "Level_PlayBgm", with this.


    moveq #0, D0
    move.b ($FFFFFE10).w, d0 ; $FFFFFE10
    lea (MusicList).l,a1 ; load music playlist
    move.b (a1,d0.w),d0 ; add d0 to a1
    move.w d0, ($FFFFFF90).w ; Fixed for Level Music continue after item wears out.
    bsr.w PlayMusic ; play music
    move.b #$34,($FFFFD080).w ; load title card object


    Next, go to "Resume Music"


    ResumeMusic: ; XREF: Obj64_Wobble; Sonic_Water; Obj0A_ReduceAir
    cmpi.w #$C,($FFFFFE14).w ; branch if countdown hasn't started yet
    bhi.s loc_140AC
    move.w #$82,d0 ; play LZ music
    cmpi.w #$103,($FFFFFE10).w ; check if level is 0103 (SBZ3)
    bne.s loc_140A6
    move.w #$86,d0 ; play SBZ music
    You see, in stock Sonic 1, you have all these conditions. With this next fix, we'll cut all the crap out and make the code simple.


    ResumeMusic: ; XREF: Obj64_Wobble; Sonic_Water; Obj0A_ReduceAir
    cmpi.w #$C,($FFFFFE14).w
    bhi.s loc_140AC
    tst.b ($FFFFF7AA).w
    bne.w ResumeBossMusic ; branch if not in a boss fight
    move.w ($FFFFFF90).w,d0 ; Fixed Drowning Recovery
    bne.w loc_140A6
    ResumeBossMusic:
    move.w #$93,d0 ; prepare to play boss music 

    Since I took out all those conditions, now the music will return to whatever the track was. No need to specify SBZ or LZ. With this fix, you can add in water in any level and not have to add in conditions per zone.

    The next fix is for Sonic's invisibility. In stock Sonic 1, the Sonic object has it's own playlist to return to once the music finishes. Why? I have no idea, but with this next fix, we can solve that.

    Here is the stock code.


    Obj01_ChkInvin:
    ; don't touch the code above the first line seen here.
    moveq #0,d0
    move.b ($FFFFFE10).w,d0
    cmpi.w #$103,($FFFFFE10).w ; check if level is SBZ3
    bne.s Obj01_PlayMusic
    moveq #5,d0 ; play SBZ music

    Obj01_PlayMusic:
    lea (MusicList2).l,a1
    move.b (a1,d0.w),d0
    jsr (PlaySound).l ; play normal music 

    Here is the fixed version.


    Obj01_ChkInvin:
    ; don't touch the code above the first line seen here.
    move.w ($FFFFFF90).w, D0 ; fixed Resume Music
    jsr PlayMusic ; (loc_1872)
    Once again, this serves the same purpose as seen in "ResumeMusic." This removes the need for the second playlist. So go find "MusicList2" and delete everything relating to it.

    Next fixes are the bosses themselves. In stock Sonic 1, the music after defeating the boss is hard coded. So, say you defeated the GHZ boss, but you want it to load in MZ. You'd have to manually change the music value that way it will play the MZ music once the boss is defeated. This is of course is an example, but it is still important to remember.

    In this next fix, we will rectify these issues.

    First go to "loc_179E0"


    loc_179E0:
    clr.w $12(a0)
    move.w #$81,d0
    jsr (PlaySound).l ; play GHZ music


    Replace it with this.


    loc_179E0:
    clr.w $12(a0)
    move.w ($FFFFFF90).w,d0 ; Fixed Boss beat music 1
    jsr (PlayMusic).l ; play GHZ music


    Next, go to "loc_1856C". Once again replace this.


    loc_1856C:
    clr.w $12(a0)
    move.w #$83,d0
    jsr (PlayMusic).l ; play MZ music


    With this


    loc_1856C:
    clr.w $12(a0)
    move.w ($FFFFFF90).w,d0 ; Fixed Boss beat music 2
    jsr (Playmusic).l ; play MZ music


    Now, for to the sake of simplicity, and that I also doubt any of you are stupid, here is a list of routines. Follow the same pattern as the first two examples.

    Routines similar to this.

     - loc_18BB4

     - loc_194E0

     - loc_18112

    Also, let's modify "Addpoints". Though it really won't make much of a difference at the moment, it will later.

    So, go to "Addpoints".


    AddPoints:
    move.b #1,($FFFFFE1F).w ; set score counter to update
    lea ($FFFFFFC0).w,a2



    Change it with this.


    AddPoints:
    move.b #1,($FFFFFE1F).w ; set score counter to update
    lea ($FFFFFED6).w,a2


    This is exactly the same as Sonic 2 Rev 2. 
     

    This my friends is how we simplify some of the code in Sonic 1. This by itself is just a tutorial, but since the mission is to port the Sonic 2 rev 2 (fixed) Driver into Sonic 1, let us continue. 

    Step Two: Fixing the VBlank.

    Now, in Sonic 1, a lot of you will say, there is no VBlank. Well, there is, but it's under another name, "loc_B10"

    The first step is to change that name. So, using your replace command, find "loc_B10", and replace it with "VBlank". This will speed up the process, and thus stop some confusion.

    Next step, we're going to rename some labels.

    - "loc_B88" to "VB_Routine1"

    - "off_B6E" to "VBlank_Index"

    - "loc_C32" to "VB_Routine2"

    Once again, simplicity for later in this section.

    Now, let's go back and look at your VBlank. For now, you'll probably see this.


    VBlank:
    movem.l d0-a6,-(sp)
    tst.b ($FFFFF62A).w
    beq.s VB_Routine1
    move.w ($C00004).l,d0
    move.l #$40000010,($C00004).l
    move.l ($FFFFF616).w,($C00000).l
    btst #6,($FFFFFFF8).w
    beq.s loc_B42
    move.w #$700,d0


    Replace it with this.


    VBlank: ; XREF: Vectors
    movem.l d0-a6,-(sp)
    tst.b ($FFFFF62A).w
    beq.s VB_Routine1
    loc_B3A:
    move.w ($C00004).l,d0
    andi.w #8, D0
    beq.s loc_B3A
    move.l #$40000010,($C00004).l
    move.l ($FFFFF616).w,($C00000).l
    btst #6,($FFFFFFF8).w
    beq.s loc_B42
    move.w #$700,d0


    To be honest, I don't think this makes a huge difference, but it is exactly how S2F is, so that should be good enough explanation.

    Next step. Find "loc_B5E". Found it? Good. Now delete that son of a bitch. Kill it. Kill it with fire. Why? Because that is what initiates the old S1 sound driver. So, that's why I'm saying to kill it.

    Next, go down to "VB_Routine1". It's time to fix it and make it work like in Sonic 2. This is what you should have.


    VB_Routine1: ; XREF: VBlank; VBlank_Index
    cmpi.b #$8C,($FFFFF600).w
    beq.s loc_B9A
    cmpi.b #$C,($FFFFF600).w
    bne.w loc_B5E



    You'll be quick to not that it has that old pesky "loc_B5E". Let's remedy that.


    VB_Routine1: ; XREF: VBlank; VBlank_Index
    cmpi.b #$8C,($FFFFF600).w
    beq.s loc_B9A ;Change 1
    cmpi.b #$C,($FFFFF600).w
    bne.w loc_B64 ;Change 3 Added in sub
    btst #0,($A11100).l ; $00A11100
    bsr Sound_Driver_Input ; Offset_0x00104C
    move.w #0, ($A11100).l ; $00A11100


    You'll be quick to note that "Sound_Driver_Input" or "sndDriverInput" from S2F, has now been placed. We'll get to that later. But first, go to the next routine. Once again, we see "loc_B5E". Let's fix that as well.


    loc_B9A:
    cmpi.b #1,($FFFFFE10).w ; is level LZ ?
    bne.w loc_B5E ; if not, branch
    move.w ($C00004).l,d0
    btst #6,($FFFFFFF8).w
    beq.s loc_BBA
    move.w #$700,d0


    Change it to.


    loc_B9A: ;Change 4.
    cmpi.b #1,($FFFFFE10).w ; is level LZ ?
    beq loc_BBA ; if not, branch
    move.w ($C00004).l,d0
    btst #6,($FFFFFFF8).w
    beq.s loc_BBA
    move.w #$700,d0


    Next, go to "loc_C22".


    loc_C22: ; XREF: loc_BC8
    move.w ($FFFFF624).w,(a5)
    move.w #0,($A11100).l
    bra.w loc_B5E 
    And would ya look at that. It seems good ol' "loc_B5E" just won't die. In this case, you're about to add in quite a few lines, so be prepared.


    loc_C22: ; XREF: loc_BC8
    move.w ($FFFFF624).w,(a5)
    move.w #$8230, ($C00004).l ; $00C00004
    bsr Sound_Driver_Input ; Offset_0x00104C
    move.w #0, ($A11100).l ; $00A11100
    bra loc_B64
    loc_C28:
    move.w ($C00004).l, D0 ; $00C00004
    move.l #$40000010,($C00004).l ; $00C00004
    move.l ($FFFFF616).w,($C00000).l ; $00C00000
    btst #6,($FFFFFFD8).w
    beq.s loc_C2D
    move.w #$700, D0
    loc_C2C:
    dbra D0, loc_C2C
    loc_C2D:
    move.w #1,($FFFFF644).w
    move.w ($FFFFF624).w,($C00004).l ; $00C00004
    move.w #$8230, ($C00004).l ; $00C00004
    move.l ($FFFFF61E).w,($FFFFEEEC).w
    move.w #$100,($A11100).l ; $00A11100
    loc_C32:
    btst #0,($A11100).l ; $00A11100
    bne.s loc_C32
    lea ($C00004).l, A5 ; $00C00004
    move.l #$94019340, (A5)
    move.l #$96FC9500, (A5)
    move.w #$977F, (A5)
    move.w #$7800, (A5)
    move.w #$83, ($FFFFF640).w
    move.w ($FFFFF640).w, (A5)
    bsr Sound_Driver_Input ; Offset_0x00104C
    move.w #0,($A11100).l ; $00A11100
    bra loc_B64
    ; ===========================================================================
    VB_Routine2: ; XREF: VBlank_Index


    Bear in mind, I put "VB_Routine2" just for reference. There is no need to copy that line as well.

    Time to now add in all the Sound Driver Initialization, so here we go.

    Go to "loc_D50" and "loc_F54". Add this line at the very beginning of each routine.


    bsr Sound_Driver_Input ; Offset_0x00104C



    Next, go to "loc_DAE"


    loc_DAE:
    ; leave all the code above this alone
    move.w #$83,($FFFFF640).w
    move.w ($FFFFF640).w,(a5)
    move.w #0,($A11100).l
    bsr.w PalCycle_SS
    ; leave all the code below this alone
    Replace it with this.


    loc_DAE:
    ; leave all the code above this alone
    move.w #$83,($FFFFF640).w
    move.w ($FFFFF640).w,(a5)
    bsr.w (Sound_Driver_Input) ; Offset_0x00104C
    move.w #0,($A11100).l
    bsr.w PalCycle_SS
    ; leave all the code below this alone

    Next, go to "loc_FAE" and replace this.


    loc_FAE:
    ; leave all the code above this alone
    move.w #$83,($FFFFF640).w
    move.w ($FFFFF640).w,(a5)
    move.w #0,($A11100).l ; start the Z80
    ; leave all the code below this alone


    With this.


    loc_FAE:
    ; leave all the code above this alone
    move.w #$83,($FFFFF640).w
    move.w ($FFFFF640).w,(a5)
    bsr.w Sound_Driver_Input ; Offset_0x00104C
    move.w #0,($A11100).l ; start the Z80
    ; leave all the code below this alone


    Find "loc_10D4" and do the same thing. Just follow the pattern, and you should be fine.

    Step Three: Adding the Sound Driver Initialization.

    Find "JoypadInit". Add this piece of code right before this routine.


    ;===============================================================================
    ; Sub Rotina para colocar o som selecionado no Driver de Som
    ; [ Início ]
    ;===============================================================================
    Sound_Driver_Input: ; Offset_0x00104C:
    lea ($FFFFC0).l, A0
    lea ($A01B80).l, A1
    cmpi.b #$80, $0008(A1)
    bne.s loc_118C
    move.b $0000(A0), D0
    beq.s loc_116C
    clr.b $0000(A0)
    bra.s loc_1176
    loc_116C:
    move.b $0004(A0), D0
    beq.s loc_118C
    clr.b $0004(A0)
    loc_1176:
    move.b D0, D1
    subi.b #$FE, D1
    bcs.s loc_1188
    addi.b #$7F, D1
    move.b D1, $0003(A1)
    bra.s loc_118C
    loc_1188:
    move.b D0, $0008(A1)
    loc_118C:
    moveq #$03, D1
    loc_118E:
    move.b $01(A0, D1), D0
    beq.s loc_11A2
    tst.b $09(A1, D1)
    bne.s loc_11A2
    clr.b $01(A0, D1)
    move.b D0, $09(A1, D1)
    loc_11A2:
    dbra D1, loc_118E
    rts
    ;===============================================================================
    ; Sub Rotina para colocar o som selecionado no Driver de Som
    ; [ Término ]
    ;===============================================================================


    That's right. We are now to that point. But we still aren't completely done. 

    This will be the last time you will see this line. Go to "Joypad_WaitZ80"


    Joypad_WaitZ80:
    btst #0,($A11100).l ; has the Z80 stopped?
    bne.s Joypad_WaitZ80 ; if not, branch
    moveq #$40,d0
    move.b d0,($A10009).l ; init port 1 (joypad 1)
    move.b d0,($A1000B).l ; init port 2 (joypad 2)
    move.b d0,($A1000D).l ; init port 3 (extra)
    move.w #0,($A11100).l ; start the Z80


    Replace it with this.


    Joypad_WaitZ80:
    btst #0,($A11100).l ; has the Z80 stopped?
    bne.s Joypad_WaitZ80 ; if not, branch
    moveq #$40,d0
    move.b d0,($A10009).l ; init port 1 (joypad 1)
    move.b d0,($A1000B).l ; init port 2 (joypad 2)
    move.b d0,($A1000D).l ; init port 3 (extra)
    bsr Sound_Driver_Input ; Offset_0x00104C
    move.w #0,($A11100).l ; start the Z80
    rts


    With that, we have finally finished initializing the driver. Now, time to actually make it work.

    Step Four: Loading the Sound Driver and making it work.

    Go to "SoundDriverLoad". You'll be quick to note that there is no actual Sound Driver being loaded, ironically enough. So, we're going to fix that.


    SoundDriverLoad: ; XREF: GameClrRAM; TitleScreen
    nop
    move.w #$100,($A11100).l ; stop the Z80
    move.w #$100,($A11200).l ; reset the Z80
    lea (Kos_Z80).l,a0 ; load sound driver
    lea ($A00000).l,a1
    bsr.w KosDec ; decompress
    move.w #0,($A11200).l
    nop
    nop
    nop
    nop
    move.w #$100,($A11200).l ; reset the Z80
    move.w #0,($A11100).l ; start the Z80
    rts
    ; End of function SoundDriverLoad


    Replace it with this.


    SoundDriverLoad: ; XREF: GameClrRAM; TitleScreen
    nop
    jmp (Sound_Driver).l ; Offset_0x0EC000
    move.w #$0100,($A11100).l ; $00A11100
    move.w #$0100,($A11200).l ; $00A11200
    lea ($A00000).l, A1 ; $00A00000
    move.b #$F3, (A1)+
    move.b #$F3, (A1)+
    move.b #$C3, (A1)+
    move.b #$00, (A1)+
    move.b #$00, (A1)+
    move.w #$0000,($A11200).l ; $00A11200
    nop
    nop
    nop
    nop
    move.w #$0100,($A11200).l ; $00A11200
    move.w #$0000,($A11100).l ; $00A11100
    rts
    ; End of function SoundDriverLoad


    Next. we need to fix the music/sound playing routines. Replace all this.


    PlaySound:
    move.b d0,($FFFFF00A).w
    rts
    ; End of function PlaySound

    ; ---------------------------------------------------------------------------
    ; Subroutine to play a special sound/music (E0-E4)
    ;
    ; E0 - Fade out
    ; E1 - Sega
    ; E2 - Speed up
    ; E3 - Normal speed
    ; E4 - Stop
    ; ---------------------------------------------------------------------------

    ; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||


    PlaySound_Special:
    move.b d0,($FFFFF00B).w
    rts
    ; End of function PlaySound_Special

    ; ===========================================================================
    ; ---------------------------------------------------------------------------
    ; Unused sound/music subroutine
    ; ---------------------------------------------------------------------------

    PlaySound_Unk:
    move.b d0,($FFFFF00C).w
    rts

    ; ---------------------------------------------------------------------------
    ; Subroutine to pause the game
    ; ---------------------------------------------------------------------------


    With this.


    PlayMusic: ; Offset_0x00131A:
    tst.b ($FFFFFFC0).w
    bne.s PlayMusic_2 ; Offset_0x001326
    move.b D0, ($FFFFFFC0).w
    rts
    PlayMusic_2: ; Offset_0x001326:
    move.b D0, ($FFFFFFC4).w
    rts
    PlaySound: ; Offset_0x00132C:
    move.b D0, ($FFFFFFC1).w
    rts
    PlaySoundStereo: ; Offset_0x001332:
    move.b D0, ($FFFFFFC2).w
    rts
    PlaySoundLocal: ; Offset_0x001338:
    tst.b $0001(A0)
    bpl.s Offset_0x001342
    move.b D0, ($FFFFFFC1).w
    Offset_0x001342:
    rts


    Woohoo, now, let's fix your pause and whatnot.

    Replace this.


    PauseGame: ; XREF: Level_MainLoop; et al
    nop
    tst.b ($FFFFFE12).w ; do you have any lives left?
    beq.s Unpause ; if not, branch
    tst.w ($FFFFF63A).w ; is game already paused?
    bne.s loc_13BE ; if yes, branch
    btst #7,($FFFFF605).w ; is Start button pressed?
    beq.s Pause_DoNothing ; if not, branch

    loc_13BE:
    move.w #1,($FFFFF63A).w ; freeze time
    move.b #1,($FFFFF003).w ; pause music

    loc_13CA:
    move.b #$10,($FFFFF62A).w
    bsr.w DelayProgram
    tst.b ($FFFFFFE1).w ; is slow-motion cheat on?
    beq.s Pause_ChkStart ; if not, branch
    btst #6,($FFFFF605).w ; is button A pressed?
    beq.s Pause_ChkBC ; if not, branch
    move.b #4,($FFFFF600).w ; set game mode to 4 (title screen)
    nop
    bra.s loc_1404
    ; ===========================================================================

    Pause_ChkBC: ; XREF: PauseGame
    btst #4,($FFFFF604).w ; is button B pressed?
    bne.s Pause_SlowMo ; if yes, branch
    btst #5,($FFFFF605).w ; is button C pressed?
    bne.s Pause_SlowMo ; if yes, branch

    Pause_ChkStart: ; XREF: PauseGame
    btst #7,($FFFFF605).w ; is Start button pressed?
    beq.s loc_13CA ; if not, branch

    loc_1404: ; XREF: PauseGame
    move.b #$80,($FFFFF003).w

    Unpause: ; XREF: PauseGame
    move.w #0,($FFFFF63A).w ; unpause the game

    Pause_DoNothing: ; XREF: PauseGame
    rts
    ; ===========================================================================

    Pause_SlowMo: ; XREF: PauseGame
    move.w #1,($FFFFF63A).w
    move.b #$80,($FFFFF003).w
    rts
    ; End of function PauseGame


    With this.


    PauseGame: ; XREF: Level_MainLoop; et al
    nop
    tst.b ($FFFFFE12).w ; do you have any lives left?
    beq.s Unpause ; if not, branch
    tst.w ($FFFFF63A).w ; is game already paused?
    bne.s loc_13BE ; if yes, branch
    btst #7,($FFFFF605).w ; is Start button pressed?
    beq.s Pause_DoNothing ; if not, branch

    loc_13BE:
    move.w #1,($FFFFF63A).w ; freeze time
    move.b #$FE, ($FFFFFFC0).w

    loc_13CA:
    move.b #$10,($FFFFF62A).w
    bsr.w DelayProgram
    tst.b ($FFFFFFE1).w ; is slow-motion cheat on?
    beq.s Pause_ChkStart ; if not, branch
    btst #6,($FFFFF605).w ; is button A pressed?
    beq.s Pause_ChkBC ; if not, branch
    move.b #4,(GameMode).w ; set game mode to 4 (title screen)
    nop
    bra.s loc_1404
    ; ===========================================================================

    Pause_ChkBC: ; XREF: PauseGame
    btst #4,($FFFFF604).w ; is button B pressed?
    bne.s Pause_SlowMo ; if yes, branch
    btst #5,($FFFFF605).w ; is button C pressed?
    bne.s Pause_SlowMo ; if yes, branch

    Pause_ChkStart: ; XREF: PauseGame
    btst #7,($FFFFF605).w ; is Start button pressed?
    beq.s loc_13CA ; if not, branch

    loc_1404: ; XREF: PauseGame
    move.b #$FF, ($FFFFFFC0).w

    Unpause: ; XREF: PauseGame
    move.w #0,($FFFFF63A).w ; unpause the game

    Pause_DoNothing: ; XREF: PauseGame
    rts
    ; ===========================================================================

    Pause_SlowMo: ; XREF: PauseGame
    move.w #1,($FFFFF63A).w
    move.b #$FF, ($FFFFFFC0).w
    rts
    ; End of function PauseGame


    Last but not, least, let's actually add in the Driver, shall we?

    Look for "Go_SoundTypes". Everything from that point and below shall be replaced with this.


    Sound_Driver: ; Offset_0x0EC000:
    include "Sound Driver/S2rev2Driver.asm"



    Now, since we have all this business squared away, lets go ahead and build. And, it doesn't. Which leads us to our next step.

    Step Five: Music fixes and whatnot.

    So now that we have all our initialization squared away, our Sound Driver loading squared away, let's go ahead and actually make this work.

    First step, find "PlaySound_Special" and replace it with "PlaySound".

    Why? It'll make our life's a hell of a lot better than if we didn't do this. As a test, go and build the damn thing. If it doesn't crash at the title screen, go and access level select and go play sounds A0 and up. That right there is proof that the driver is fully operational. Since we know that now, let's move on.

    Before we make any music fixes, let's go on and fix the Sound Test in Level Select. Replace this.


    LevSel_NoCheat:
    cmpi.w #$94,d0 ; is sound $80-$94 being played?
    bcs.s LevSel_PlaySnd ; if yes, branch
    cmpi.w #$A0,d0 ; is sound $95-$A0 being played?
    bcs.s LevelSelect ; if yes, branch


    with this.


    LevSel_NoCheat:
    cmpi.w #$A0,d0 ; is sound $80-$94 being played?
    ; Fixed Equivalent to S2
    bcs.s LevSel_PlaySnd ; if yes, branch
    cmpi.w #$A0,d0 ; is sound $95-$A0 being played?
    bcs.s LevelSelect ; if yes, branch 

    This part of the tutorial is essentially a quick guide on how to extend the Sound Test. Aren't I the nicest?

    Go to "LevSel_SndTest:" and change this.


    LevSel_SndTest: ; XREF: LevSelControls
    cmpi.w #$14,($FFFFFF82).w ; is item $14 selected?
    bne.s LevSel_NoMove ; if not, branch
    move.b ($FFFFF605).w,d1
    andi.b #$C,d1 ; is left/right pressed?
    beq.s LevSel_NoMove ; if not, branch
    move.w ($FFFFFF84).w,d0
    btst #2,d1 ; is left pressed?
    beq.s LevSel_Right ; if not, branch
    subq.w #1,d0 ; subtract 1 from sound test
    bcc.s LevSel_Right
    moveq #$4F,d0 ; if sound test moves below 0, set to $4F

    LevSel_Right:
    btst #3,d1 ; is right pressed?
    beq.s LevSel_Refresh2 ; if not, branch
    addq.w #1,d0 ; add 1 to sound test
    cmpi.w #$50,d0
    bcs.s LevSel_Refresh2
    moveq #0,d0 ; if sound test moves above $4F, set to 0


    With this.


    LevSel_SndTest: ; XREF: LevSelControls
    cmpi.w #$14,($FFFFFF82).w ; is item $14 selected?
    bne.s LevSel_NoMove ; if not, branch
    move.b ($FFFFF605).w,d1
    andi.b #$C,d1 ; is left/right pressed?
    beq.s LevSel_NoMove ; if not, branch
    move.w ($FFFFFF84).w,d0
    btst #2,d1 ; is left pressed?
    beq.s LevSel_Right ; if not, branch
    subq.w #1,d0 ; subtract 1 from sound test
    bcc.s LevSel_Right
    moveq #$7F,d0 ; if sound test moves below 0, set to $4F
    ; Limit now to FF going left

    LevSel_Right:
    btst #3,d1 ; is right pressed?
    beq.s LevSel_Refresh2 ; if not, branch
    addq.w #1,d0 ; add 1 to sound test
    cmpi.w #$80,d0 ; Limit now to FF going right
    bcs.s LevSel_Refresh2
    moveq #0,d0 ; if sound test moves above $4F, set to 0
     
    There. Done with the Sound Test fixes. Now time for music fixes.

    Stop music fix:

    Go search for this piece of code in your search box.


    move.b #$E4,d0


    Replace every instance with this


    move.b #$FD,d0




    Fade Out Music Fix:

    Go into your search box and find these lines. Ensure they are together.


    move.b #$E0,d0
    bsr.w PlaySound_Special ; fade out music


    Replace all instances with these.


    move.b #$F9,d0 ; Fade out fix
    bsr.w PlaySound ; fade out music fade out music



    Fix Sega Sound:

    Go to "Sega_WaitPallet" and replace this.


    move.b #$E1,d0
    bsr.w PlaySound_Special ; play "SEGA" sound


    with this.


    move.b #$FA,d0
    bsr.w PlaySound ; play "SEGA" sound



    Fix Title Screen Music.

    Go to "Title_LoadText" and change this.


    move.b #$8A,d0 ; play title screen music
    bsr.w PlaySound_Special


    with this.


    move.b #$99,d0 ; play title screen music
    bsr.w PlayMusic



    Special Stage Music Fix.

    Go to "SS_ClrNemRam" and replace this.


    move.w #$89,d0
    bsr.w PlaySound ; play special stage BG music
    with this.


    move.w #$92,d0 ; Fixed Special Stage Music
    bsr.w PlaySound ; play special stage BG music


    Continue Screen Music Fix.

    Go to "Cont_ClrObjRam" and change this.


    move.b #$90,d0
    bsr.w PlaySound ; play continue music


    to this.


    move.b #$9C,d0 ; Fixed Continue Screen
    bsr.w PlaySound ; play continue music 
    Ending and Credits Music Fix.

    Now, there is several tracks that could fit this, but I'll use the S2's Sweet Dreams as the song that plays during Sonic's running sequence, and obviously load the Ending medley during the credits.

    First, go to "End_LoadData" and change this.


    move.w #$8B,d0
    bsr.w PlaySound ; play ending sequence music


    to this.


    move.w #$95,d0 ; End Run music fix, aka Sweet Dreams.
    bsr.w PlaySound ; play ending sequence music


    This fixes the ending sequence, and plays something a bit more appropriate, as opposed to MCZ.

    Now, to the credits. Go to "End_MainLoop" and change this.


    move.b #$91,d0
    bsr.w PlaySound_Special ; play credits music 
    to this.


    move.b #$9E,d0 ; Corrected Ending Credits.(Fix)
    bsr.w PlaySound ; play credits music 

    That should fix all the main problems with different screens. But for an added bonus, let's go ahead and in music into the Level Select.

    First, go into "Title_ChkLevSel". Change this.


    lea ($FFFFCC00).w,a1


    Into this.


    lea ($FFFFCC00).w,a1
    move.b #$91,d0 ; Added.(Fix)
    bsr.w PlayMusic ; play Options/LS music 
    This should now give you that S2B Level Select feeling now. So, have a blast. But now that is officially all the Main game modes that have had their music fixed (or in this case added). So now, let's move onto those other fixes that need to be addressed.

    Extra lives fix.

    Go into your search bar, and look for this.


    move.w #$88,d0


    Replace it with this.


    move.w #$98,d0



    Since we are here, let's go ahead and fix a few monitor issues that are present.

    Monitor Fixes:

    Go to "Obj2E_ChkShoes" and change this line.


    move.w #$E2,d0
    jmp (PlaySound).l ; Speed up the music
    with this.


    move.w #$FB,d0 ; Fixed Speed Shoes
    jmp (PlayMusic).l ; Speed up the music 

    Go to "Obj2E_ChkInvinc" and change this line.


    move.w #$87,d0
    jmp (PlaySound).l ; play invincibility music
    with this.


    move.w #$97,d0 ; Fixed Invincibility
    jmp (PlaySound).l ; play invincibility music


    Now, let's move on to other minor sound effect issues.

    Waterfall, slide, and LZ Water Tunnel fixes.

    In Sonic 2, it is unfortunate to say this sound doesn't outright exist anywhere. With that said, there is an alternate sound that can and will be used instead.

    So, once again, go into your handy dandy search and replace and find this.


    move.w #$D0,d0
    jsr (PlaySound_Special).l
    Now, replace all instances with this.


    move.w #$F0,d0 ; Waterfall Sound fix
    jsr (PlaySound).l
    There is only three of these around, so if you really felt the need to manually do it without the mass replace, you could simply look up the first line.

    Level/SS completed music fix.

    It seems that CPZ plays as the level complete. Unless you like it like that, go and search for this.


    move.w #$8E,d0
    jsr (PlaySound_Special).l


    And replace all instances with this.


    move.w #$9A,d0 ; Fixed End of Level music
    jsr (PlaySound).l



    Fixed Drowning Music.

    This is a pretty simple fix, and unless you tend to run out of air, you'd probably never notice it.

    Go to "Obj0A_Countdown" and replace this.


    move.w #$92,d0


    With this.


    move.w #$9F,d0 ; fixed Drowning


    Fixed Speed Shoes.

    Go to "Obj01_ChkShoes". Change this.


    move.w #$E3,d0
    jmp (PlaySound).l ; run music at normal speed


    to this.


    move.w #$FC,d0
    jmp (PlaySound).l ; loc_14C0  

    Special Stage Sound Effect fixes.

    Go to "Obj09_NoEmer" and change this.


    move.w #$93,d0


    to this.


    move.w #$9D,d0 ; Fixed Emerald Collect Sound


    Go to "Obj09_GOAL" and change this.


    move.w #$A8,d0 ; change item


    to this.


    move.w #$ED,d0 ; Fixed lose


    Now, time to fix the warp sounds. Find this line.


    move.w #$A8,d0


    Replace all instances with this.


    move.w #$CA,d0 ; Fixed warp out

    Minor Sound Effect fixes.

    We only have two more sfx issues to fix. Luckily they are minor, and are only present in one level, MZ. 

    First, When Sonic pushes an object, it sounds weird. Unfortunately, there is no real equivalent to this sound, because no build of Sonic 2 since Nick Arcade has needed it. So, once again, this is going to be one of those, "find the closest" game. So, go to "loc_C294" and find these two lines.


    move.w #$A7,d0
    jsr (PlaySound_Special).l ; play pushing sound


    Unless you like Sonic sounding like a twinkling vampire, change it to this.


    move.w #$AB,d0
    jsr (PlaySound).l ; play pushing sound



    Next fix is the Batbot. Luckily, there is a near exact version, so go to "Obj55_PlaySnd". Change this.


    move.w #$C0,d0
    jsr (PlaySound_Special).l ; play flapping sound


    To this.


    move.w #$DB,d0
    jsr (PlaySound).l ; play flapping sound
    With that last piece of code. That fixes all the sound effect issues. Now, there is two more issues to tackle.

    Boss Music.

    As much as I love EHZ 2pl, I doubt you'd like it in a boss battle, so let's have your bosses to play the correct music.

    Go and find this line.


    move.w #$8C,d0
    bsr.w PlaySound ; play boss music


    Replace all instances with this line.


    move.w #$93,d0 ; Fixed Boss Music
    bsr.w PlayMusic ; play boss music


    Now you have fixed boss music...almost.

    This next fix is optional ,and if you prefer having whatever song playing during this play, go all for it. But for this tutorial, I've decided to add in music for the Final Boss. 

    Go to "Resize_FZend" and add this to the end of the routine.


    move.w #$94,d0 ; Added Final Boss Music
    bsr.w PlayMusic ; play boss music




    With that, this finishes up all the fixes of Sound and Music...except for the last thing....The music list.

    Music List:

    What? I forgot to fix that, and just remembered now? No. I would have added this earlier if I felt like it. Why didn't I? Because this next fix is one for you guys to fix. All I'm providing you with is a template. So, without further ado, let me give you a replacement for that pesky old Music List.

    In the current disassembly, go to "Musiclist"


    MusicList: binclude misc/muslist1.bin
    align 2


    Replace it with this.


    MusicList:
    dc.b $82 ; GHZ Music
    dc.b $87 ; LZ Music
    dc.b $86 ; MZ Music
    dc.b $8D ; SLZ Music
    dc.b $89 ; SYZ Music
    dc.b $85 ; MZ Music
    dc.b $8A ; SBZ Music
    align 2


    Now. This list has the music that would "best" fit each zone. You of course can change the values. Thus why it's a template. I personally have no issues with it, but feel free to change the music however you see fit.

    Conclusion

    Hopefully, if you've succeeded in following all of the steps, you now have a fully functioning Sonic 2 (fixed) Driver in play. Special Thanks to Esrael for releasing the disassembly in the first place. Also, special thanks to Vladikcomper who modified the S2B4 Driver and fixed the z80 for me. Of course, I adapted it to work with S2rev2's music and sfx, nevertheless, he is the coolest guy around. Also, a quick shoutout to djohe who pointed out a small little tiny issue with the "Obj01_ChkInvin" code. Also, thanks to Kram1024 for the initial guide. 

    edit: Added in Speed Shoe fix. Whoopsies =P
     
    Last edited by a moderator: Apr 13, 2013
    KCEXE likes this.
  2. nineko

    nineko I am the Holy Cat Member

    Joined:
    Mar 24, 2008
    Messages:
    1,902
    Location:
    italy
    My name is nineko and I hate the Sonic 1 driver, so I look forward to where this is going.

    In my hack I did some of the "simplifications" you suggest here, too, but in a slightly different way. It's good to use a RAM address to store the song which is currently playing, it comes really handy in several occasions, such -- as you said yourself -- bosses and water levels. If you want to overdo it and cover ALL possible cases, though, put yourself in the worst possible scenario: custom layout, with water and an invincibility monitor in a boss arena. It's not as trivial to resume the correct music there :p

    (I think I didn't cover all the cases in my hack, either)

    By the way, this is a tutorial. Not sure why you posted it in Showroom.

    *moves*

    Now please continue.

    *sits back and waits for developments*
     
    Last edited by a moderator: Apr 13, 2013
  3. ThomasThePencil

    ThomasThePencil resident psycho Member

    Joined:
    Jan 29, 2013
    Messages:
    910
    Location:
    the united states. where else?
    I would love this if I didn't hate the Sonic 2 sound driver purely because of how hard it is to work with :U

    Regardless, I do still like the guide. It's very well written and very well thought out.

    Now we need another sound driver porting guide: Porting the S&K sound driver to Sonic 2.

    *runs*
     
  4. SuperEgg

    SuperEgg I'm a guy that knows that you know that I know Member

    Joined:
    Oct 17, 2009
    Messages:
    Location:
    THE BEST GOD DAMN STATE OF TEXAS
    Actually Nineko, I fixed that issue and is reflected in the current tutorial. Boss music is now a condition in the MusicRestore routine, so bite me =P

    Also, thanks for moving it in here. I have no idea why I left it out there, but it probably has to do with me being tired at the time of when I started writing it.

    Kiss Kiss.
     
Thread Status:
Not open for further replies.