Make Sonic 1's Sound Driver (Slightly) Better

Discussion in 'Engineering & Reverse Engineering' started by Advanced?, Dec 11, 2019.

  1. Advanced?


    Sonic 1 Hack
    Note: Read further down for more fixes, and I recommend going here for even more fixes.

    You've probably read Clownacy's post on making Sonic 2's Sound Driver Good, but some people may prefer the Sonic 1 Driver due to its flexibility. Well, here's how you can improve it in various ways.

    Please note this is designed with my AS disassembly, which can be found here.

    Optimizing WriteFMI/WriteFMII
    Wow both this and Clownacy's guide both start with optimizing WriteFMI/WriteFMII... interesting...

    Sonic 1 seems to be using a modified (early?) 68K Type 1b driver. One of its weird oddities is that the "WriteFMI" and "WriteFMII" instructions are really unoptimized. So why not optimize it?

    In s1.sounddriver.asm at WriteFMI: you'll see this monstrosity of nature.
    Code (Text):
    1. WriteFMI:                ; XREF: loc_71E6A
    2.         move.b    ($A04000).l,d2
    3.         btst    #7,d2
    4.         bne.s    WriteFMI
    5.         move.b    d0,($A04000).l
    6.         nop
    7.         nop
    8.         nop
    10. loc_72746:
    11.         move.b    ($A04000).l,d2
    12.         btst    #7,d2
    13.         bne.s    loc_72746
    15.         move.b    d1,($A04001).l
    16.         rts
    17. ; End of function WriteFMI
    19. ; ===========================================================================
    21. loc_7275A:                ; XREF: WriteFMIorII
    22.         move.b    1(a5),d2
    23.         bclr    #2,d2
    24.         add.b    d2,d0
    26. ; ||||||||||||||| S U B    R O U T    I N E |||||||||||||||||||||||||||||||||||||||
    27. ; Stangely, this is the type 1a version with some nops added.
    29. ; sub_72764:
    30. WriteFMII:                ; XREF: loc_71E6A; Sound_ChkValue; sub_7256A; WriteFMII
    31.         move.b    ($A04000).l,d2
    32.         btst    #7,d2
    33.         bne.s    WriteFMII
    34.         move.b    d0,($A04002).l
    35.         nop
    36.         nop
    37.         nop
    39. loc_7277C:
    40.         move.b    ($A04000).l,d2
    41.         btst    #7,d2
    42.         bne.s    loc_7277C
    44.         move.b    d1,($A04003).l
    45.         rts
    46. ; End of function WriteFMII
    Remove all those "nops." Now we might've saved some space, but we can take this further. Replace the above code with this:
    Code (Text):
    1. WriteFMI:                ; XREF: loc_71E6A
    2.         lea    ($A04000).l,a0
    3. -        btst    #7,(a0)
    4.         bne.s    -
    5.         move.b    d0,(a0)
    6. -        btst    #7,(a0)
    7.         bne.s    -
    8.         move.b    d1,1(a0)
    9.         rts
    10. ; End of function WriteFMI
    12. ; ===========================================================================
    14. loc_7275A:                ; XREF: WriteFMIorII
    15.         move.b    1(a5),d2
    16.         bclr    #2,d2
    17.         add.b    d2,d0
    19. ; ||||||||||||||| S U B    R O U T    I N E |||||||||||||||||||||||||||||||||||||||
    21. ; sub_72764:
    22. WriteFMII:                ; XREF: loc_71E6A; Sound_ChkValue; sub_7256A; WriteFMII
    23.         lea    ($A04000).l,a0
    24. -        btst    #7,(a0)
    25.         bne.s    -
    26.         move.b    d0,2(a0)
    27. -        btst    #7,(a0)
    28.         bne.s    -
    29.         move.b    d1,3(a0)
    30.         rts
    31. ; End of function WriteFMII
    This is from Golden Axe II (minus the "nop"), which also uses the Type 1b driver. And there we go, we just optimized the driver a bit!

    Remove Sega Z80 Code
    This should only be done if you've followed this guide. Because the Sega PCM is now being played on the 68k side, the Z80 code is useless now.

    In z80.asm, find this piece of code:
    Code (Text):
    1.     ld    a,zmake68kBank(SegaPCM)&1        ; least significant bit from ROM bank ID
    2.     ld    (zBankRegister),a                ; Latch it to bank register, initializing bank switch
    4.     ld    b,8                                ; Number of bits to latch to ROM bank
    5.     ld    a,zmake68kBank(SegaPCM)>>1        ; Bank ID without the least significant bit
    Delete it since it's no-longer needed. Not far below, you'll find this:
    Code (Text):
    1.     cp    6                                ; Is the sample 87h or higher?
    2.     jp    nc,zPlay_SegaPCM                ; If yes, branch
    Delete it too. Finally, delete all of zPlay_SegaPCM.

    Fix the Third Sound Queue
    In Sonic 1 there's a third unused sound-queue. Why is it unused? It's because a bug in the Sound Driver prevents it from working. Might as-well fix it.

    At loc_71BB2 change the "tst.w $A(a6)" to a long-word. Then at InitMusicPlayback change "move.w $A(a6),d5" a long-word. Finally right below that you'll see "move.w d5,$A(a6)," change that to a long-word too.

    Remove Bizzare Checks
    At "PlaySoundByIndex" you'll see this:
    Code (Text):
    1. PlaySoundByIndex:
    2.         moveq    #0,d7
    3.         move.b    9(a6),d7
    4.         beq.w    StopSoundAndMusic
    5.         bpl.s    locret_71F8C
    6.         move.b    #$80,9(a6)    ; reset    music flag
    7.         cmpi.b    #MusID__End+$B,d7
    8.         bls.w    PlayMusic    ; music    $81-$9F
    9.         cmpi.b    #SndID__First,d7    ; is it after MusID__End but before SndID__First? (redundant)
    10.         bcs.w    locret_71F8C
    11.         cmpi.b    #SndID__End,d7
    12.         bls.w    PlaySound_CheckRing    ; sound    $A0-$CF
    13.         cmpi.b    #SpeSndID__First,d7    ; is it after SndID__End but before SpecSndID__First? (redundant)
    14.         bcs.w    locret_71F8C
    15.         cmpi.b    #SpeSndID__End+$F,d7
    16.         bcs.w    PlaySound_CheckWaterfall    ; sound    $D0-$DF
    17.         cmpi.b    #CmdID__End,d7
    18.         bls.s    PlaySound_Effects    ; sound    $E0-$E4
    20. locret_71F8C:
    21.         rts  
    Change it to this:
    Code (Text):
    2.         moveq    #0,d7
    3.         move.b    9(a6),d7
    4.         beq.w    StopSoundAndMusic
    5.         bpl.s    locret_71F8C
    6.         move.b    #$80,9(a6)    ; reset    music flag
    7.         cmpi.b    #MusID__End+$B,d7
    8.         bls.w    PlayMusic    ; music    $81-$9F
    9.         bcs.w    locret_71F8C
    10.         cmpi.b    #SndID__End,d7
    11.         bls.w    PlaySound_CheckRing    ; sound    $A0-$CF
    12.         bcs.w    locret_71F8C
    13.         cmpi.b    #SpeSndID__End+$F,d7
    14.         bcs.w    PlaySound_CheckWaterfall    ; sound    $D0-$DF
    15.         cmpi.b    #CmdID__End,d7
    16.         bls.s    PlaySound_Effects    ; sound    $E0-$E4
    18. locret_71F8C:
    19.         rts  
    For some reason the developers added checks to see if there's any slots between $9F-$A0, and $CF-$D0, which is impossible.

    Add PlaySound_Local from Sonic 2
    In Sonic 2, a special function which makes a sound play ONLY, if an object's on-screen. Thankfully this is pretty easy to add.

    Above PlaySound, add this:
    Code (Text):
    1. ; ---------------------------------------------------------------------------
    2. ; Subroutine to    play a sound or    music track if on-screen
    3. ; ---------------------------------------------------------------------------
    5. ; ||||||||||||||| S U B    R O U T    I N E |||||||||||||||||||||||||||||||||||||||
    8. PlaySound_Local:
    9.         tst.b    1(a0)
    10.         bpl.s    +
    Then, right before the "rts" in PlaySound, add a +.

    EDIT: Updated labels
    Last edited: Dec 13, 2019
  2. Ralakimus


    Pour your misery down on me Tech Member
    While these changes are nice and all, honestly, I disagree with this "making the driver good", as it only applies a few speed optimizations and a bug fix here and there.

    The Sonic 1 sound driver is pretty much filled to the brim with silly bugs and oddities that should be fixed in order to be qualified as at least decent, in my opinion. See this for a taste.
  3. MainMemory


    Have no fear...Amy Rose is here! Tech Member
    In what way is the Sonic 1 driver inherently "more flexible" than the Sonic 2 driver?
  4. Advanced?


    Sonic 1 Hack
    Possibly mostly with its music, considering Music Tracks aren't in banks, meaning music can be added easily.
  5. MainMemory


    Have no fear...Amy Rose is here! Tech Member
  6. Advanced?


    Sonic 1 Hack
    Fading Not Clearing All Variables
    As documented in the Github disassembly, $E4 doesn't clear the last 10 bytes of the track data. To fix this, at StopSoundAndMusic, change this line:
    Code (Text):
    1.         move.w    #$E3,d0
    To this:
    Code (Text):
    1.         move.w    #$F3,d0

    SendPSGNoteOff Bug
    If InitMusicPlayback doesn't clear all the channels, there's a chance that random noises will be played. To fix this, right above locret_729B4, add these lines:
    Code (Text):
    1.         cmpi.b    #$DF,d0                ; Are stopping PSG3?
    2.         bne.s    locret_729B4
    3.         move.b    #$FF,($C00011).l        ; If so, stop noise channel while we're at it
    This code were backported from the S3K driver, which fixed the issue.

    Halted Volume Updates
    There's a issue that prevents future volume updates, which can break fading. To fix this at VolEnvHold, change these lines:
    Code (Text):
    1.         subq.b    #1,$C(a5)
    2.         rts
    To this:
    Code (Text):
    1.         subq.b    #1,$C(a5)
    2.         subq.b    #1,$C(a5)
    3.         jsr    loc_7292E
    These were also backported from the S3K driver.

    EDIT: Updated labels.
    Last edited: Dec 13, 2019