Actions

SCHG How-to

Difference between revisions of "Port the Sonic 2 Clone Sound Driver to the HG version of Sonic 2"

From Sonic Retro

(Step 1 - getting started)
m (Text replacement - "\[\[Category:SCHG How-tos.*" to "")
 
(22 intermediate revisions by 5 users not shown)
Line 1: Line 1:
{{GuideBy|Caverns4}}
+
{{GuideBy|Caverns 4}}
 +
==WARNING==
 +
<b>DO NOT USE THIS GUIDE. This is only here for archival purposes, and is using a shoddy old version of the driver. Get {{LinkRetro|topic=32801|title=Clownacy's new version of the Clone Driver}} and use that for your hacks instead.</b> ~ [[User:Caverns 4|Caverns 4]] 18:26, 8 July 2014 (UTC)
 +
 
 +
If you want proof of how shoddy the old Sonic 2 Clone Driver is, look at the list of negatives a few paragraphs down. They're all fixed the Sonic 2 Clone Driver v2. ~ [[User:Clownacy|Clownacy]]
 +
 
 
==Summary==
 
==Summary==
<b>Please note that this guide is currently in need of a few teaks, which I will be implementing once I get the chance. In the meantime, use this guide at your own risk.</b> ~ Caverns4
+
<b>The guide is fixed and updated as of September 11th, 2013. It should now work on real hardware!</b> ~ Caverns 4
  
The Sonic 2 Clone Driver is simply a modified version of the Sonic 1 Sound driver, designed to work with Sonic 2. The advantages to using this over the Sound Driver in Sonic 2 normally are numerous; It will be easier to modify existing songs as you won't have to worry about compressing and decompressing the music, and your music will be supported by more up to date [[Music editor programs]].
+
The Sonic 2 Clone Driver is simply a modified version of Sonic 1's sound driver, designed to work with Sonic 2. The advantages to using this over Sonic 2's sound driver normally are numerous; It will be easier to modify existing songs as you won't have to worry about compressing and decompressing the music, and your music will be supported by more up to date [[Music editor programs]].
  
There are a few bugs I have noticed. One is that the spindash sound will not raise pitch. The music is not a perfect adaptation of Sonic 2's music, particularly sometimes the PSG channels sound slightly different. This is most noticeable in Emerald Hill's music. Besides this, there are no problems.
+
There are many inaccuracies with the Sonic 2 Clone Driver, however. One is that the Spin Dash's rev sound will not raise pitch. The music is also not a perfect adaptation of Sonic 2's music, particularly sometimes the PSG channels sound slightly different (unless you do the optional step that adds Sonic 2 PSGs, at least.) This is most noticeable in Emerald Hill Zone's music. The tempos of some songs are also slightly different, along with the Speed Shoes tempos being outright wrong, some even <i>slowing down</i> the music. CPZ's Gloop sound will also play twice as often as it should. Sound priorities are also incorrect, leading to some sounds being able to interrupt others when they shouldn't. As is the case in Sonic 1, on PAL consoles, the music will play at a slowed speed.
  
If the above bugs will not bother you too badly, then you'll like using the Sonic 2 Clone Driver after working with Sonic 2's own sound driver. The Clone Driver is much easier to port music to, and in fact, Sonic 1 music can even just be bincluded into the ROM. This is because it's based on the Sonic 1 sound driver, and uses similar (if not the same) formatting. With this out of the way, now it's time to edit the Sonic 2 HG Dissasembly!
+
If the above bugs will not bother you too badly, then you'll like using the Sonic 2 Clone Driver after working with Sonic 2's own sound driver. The Sonic 2 Clone Driver is much easier to port music to, and in fact, Sonic 1 music can even just be binclude'd into the ROM. This is because it's based on Sonic 1's sound driver, and uses the same formatting. With this out of the way, now it's time to edit the Sonic 2 Git Disassembly!
  
Before begining, you will need the following file:
+
Before beginning, you will need the following file:
  
 
{{Download|file=Sonic 2 Clone Driver.7z|filesize=79kb|title=Sonic 2 Clone Driver Files|plural=1}}
 
{{Download|file=Sonic 2 Clone Driver.7z|filesize=79kb|title=Sonic 2 Clone Driver Files|plural=1}}
  
==Step 1 - getting started==
+
==Step 1 - Getting Started==
Back up your dissasembly if you haven't already.
+
Back up your disassembly if you haven't already.
  
 
To start, go into your sound folder, where you'll have a DAC folder, a music folder, and a PCM folder.
 
To start, go into your sound folder, where you'll have a DAC folder, a music folder, and a PCM folder.
Line 20: Line 25:
 
<b>DELETE THEM ALL!</b>
 
<b>DELETE THEM ALL!</b>
  
Also delete s2.sounddriver.asm. That's the Sonic 2 Sound Driver, so it's not necessary.
+
Also delete s2.sounddriver.asm. These are all parts of Sonic 2's sound driver, so they won't be necessary.
  
and then extract "Sonic 2 Clone Driver_fixed.7z" into the main folder of your dissasembly.
+
Then extract "Sonic 2 Clone Driver.7z" into the main folder of your disassembly.
  
==Step 2 - Deleting broken references==
+
==Step 2 - Deleting Leftovers==
Now open up s2.asm, and search for the line "; end of 'ROM'" near the end of your dissasemby.
+
Now open up s2.asm, and find the label 'SoundDriverLoad:'. Delete everything from that, up to and including:
  
On the empty line before it, past this:
+
<pre>Mus_Continue:   BINCLUDE    "sound/music/Continue.bin"</pre>
  
<asm>  include "Sonic 2 Clone Driver.asm"
+
What we have done here is deleted the routines to load and decompress Sonic 2's sound driver. We don't need this anymore.
  even</asm>
 
  
After this, search for "SoundIndex:", and delete everything for it, up to and including "SndPtr__End:"
+
Next up, find this line:
Now there are many unused sounds, Sound20 - Sound70 in the dissasembly that will be unused. If you wish, delete those too, as
 
  
they will only take space.
+
<pre> cnop -Size_of_SEGA_sound, $8000</pre>
  
Once you've done that, locate "MusicPoint2:", and delete that, and everything below it it until the following line:
+
and delete everything from there up to (but not including) the line:
 +
 +
<pre>; end of 'ROM'</pre>
 +
 +
Also, on the line above the 'EndOfRom:' label, you should see this:
  
<asm>   if * > soundBankStart + $8000</asm>
+
<pre> shared word_728C_user,Obj5F_MapUnc_7240,off_3A294,MapRUnc_Sonic,movewZ80CompSize</pre>
 +
 +
Change it to this:
  
Leave this line and everything below it alone for the time being.
+
<pre> shared word_728C_user,Obj5F_MapUnc_7240,off_3A294,MapRUnc_Sonic</pre>
  
Now find the line <asm>; loc_F1E8C:</asm>
+
Finally, find the label '<b>sndDriverInput:</b>'
  
Below this line is where the Sega sound is included. If we delete it, we will get errors. If we leave I, we will get errors. So what do we
+
Delete the entire function, which starts there, and ends at this line:
  
do? Change it!
+
<pre>; End of function sndDriverInput</pre>
Replace this:
 
<asm>; -------------------------------------------------------------------------------
 
; Sega Intro Sound
 
; 8-bit unsigned raw audio at 16Khz
 
; -------------------------------------------------------------------------------
 
; loc_F1E8C:
 
Snd_Sega:    BINCLUDE    "sound/PCM/SEGA.bin"
 
Snd_Sega_End:
 
  
    if Snd_Sega_End - Snd_Sega > $8000
+
Now search in your assembly for "<b>sndDriverInput</b>", and delete any lines that point to it. There will be quite a few, but it won't hurt anything.
        fatal "Sega sound must fit within $8000 bytes, but you have a $\{Snd_Sega_End-Snd_Sega} byte Sega sound."
+
    endif
+
We've effectively deleted the old sound driver entirely from our game... Now it's time we implemented our new one... But first, we need to prepare s2.constants.asm!
    if Snd_Sega_End - Snd_Sega > Size_of_SEGA_sound
 
        fatal "Size_of_SEGA_sound = $\{Size_of_SEGA_sound}, but you have a $\{Snd_Sega_End-Snd_Sega} byte Sega sound."
 
    endif</asm>
 
 
 
With this:
 
  
<asm>; loc_F1E8C:
+
==Step 3 - Overhauling Constants, Fixing RAM==
Snd_Sega:    rts
+
Open s2.constants.asm, and find the following line:
Snd_Sega_End:</asm>
 
  
Now, we need to delete the old BINCLUDEd DAC samples. Got to loc_ED100, or SndDAC_Start.
+
Find the line "<b>; Music IDs</b>". You'll see this:
Staring at line "; loc_ED100:", delete everything down to (But not including) this chunk of code.
 
  
<asm>; --------------------------------------------------------------------
+
<pre>; Music IDs
; Nemesis compressed art (20 blocks)
+
offset :=    zMasterPlaylist
; Buzzer's fireball
+
ptrsize :=    1
ArtNem_Buzzer_Fireball:    BINCLUDE    "art/nemesis/Fireball 1 (Buzzer).bin"
+
idstart :=   $81
; --------------------------------------------------------------------</asm>
+
; $80 is reserved for silence, so if you make idstart $80 or less,
 +
; you may need to insert a dummy zMusIDPtr in the $80 slot</pre>
  
That is art used in the game, so obviously we don't want that to get deleted.
+
Delete everything from there down to "<b>MusID__End = id(zMusIDPtr__End)  ; A0</b>", and paste the following where it used to be:
  
Right above if, you will also see this line:
+
<pre>; Music IDs
 +
; $80 is reserved for silence, so if you make idstart $80 or less,
 +
; you may need to insert a dummy zMusIDPtr in the $80 slot
 +
MusID__First =          $81
 +
MusID_2PResult =        $81
 +
MusID_EHZ =            $82
 +
MusID_MCZ_2P =          $83
 +
MusID_OOZ =            $84
 +
MusID_MTZ =            $85
 +
MusID_HTZ =            $86
 +
MusID_ARZ =            $87
 +
MusID_CNZ_2P =          $88
 +
MusID_CNZ =            $89
 +
MusID_DEZ =            $8A
 +
MusID_MCZ =            $8B
 +
MusID_EHZ_2P =          $8C
 +
MusID_SCZ =            $8D
 +
MusID_CPZ =            $8E
 +
MusID_WFZ =            $8F
 +
MusID_HPZ =            $90
 +
MusID_Options =        $91
 +
MusID_SpecStage =      $92
 +
MusID_Boss =            $93
 +
MusID_EndBoss =        $94
 +
MusID_Ending =          $95
 +
MusID_SuperSonic =      $96
 +
MusID_Invincible =      $97
 +
MusID_ExtraLife =      $98
 +
MusID_Title =          $99
 +
MusID_EndLevel =        $9A
 +
MusID_GameOver =        $9B
 +
MusID_Continue =        $9C
 +
MusID_Emerald =        $9D
 +
MusID_Credits =        $9E
 +
MusID_Countdown =      $9F
 +
MusID__End  =          $A0</pre>
  
<asm>    cnop -Size_of_DAC_samples, $8000</asm>
+
The music is all fixed, now all that's left is the sound effects:
 
 
You need to delete that too.
 
  
Finally, search for sub_EC000, or "SoundDriverLoad", which will look like this:
+
Find the line "<b>; Sound IDs</b>", and delete everything down to the line "<b>; Special sound IDs</b>". Leave the special IDs alone.
  
<asm>; ---------------------------------------------------------------------------
+
In place of the text you deleted, just paste this:
; Subroutine to load the sound driver
 
; ---------------------------------------------------------------------------
 
; sub_EC000:
 
SoundDriverLoad:
 
    move    sr,-(sp)
 
    movem.l    d0-a6,-(sp)
 
    move    #$2700,sr
 
    lea    (Z80_Bus_Request).l,a3
 
    lea    (Z80_Reset).l,a2
 
    moveq    #0,d2
 
    move.w    #$100,d1
 
    move.w    d1,(a3)    ; get Z80 bus
 
    move.w    d1,(a2)    ; release Z80 reset (was held high by console on startup)
 
-    btst    d2,(a3)
 
    bne.s    -    ; wait until the 68000 has the bus
 
    jsr    DecompressSoundDriver(pc)
 
    btst    #0,(VDP_control_port+1).l    ; check video mode
 
    sne    (Z80_RAM+zPalModeByte).l    ; set if PAL
 
    move.w    d2,(a2)    ; hold Z80 reset
 
    move.w    d2,(a3)    ; release Z80 bus
 
    moveq    #$E6,d0
 
-    dbf    d0,-    ; wait for 2,314 cycles
 
    move.w    d1,(a2)    ; release Z80 reset
 
    movem.l    (sp)+,d0-a6
 
    move    (sp)+,sr
 
    rts</asm>
 
 
 
    Delete the whole thing, as it will now do nothing but cause an error.
 
 
 
==Step 3 - Replace a bunch of stuff.==
 
Search for the routine VintRet (Search for "VintRet:"), and you'll have something like this:
 
  
<asm>VintRet:
+
<pre>; Sound IDs
    addq.l    #1,(Vint_runcount).w
+
SndID__First =                  $A0
    movem.l    (sp)+,d0-a6
+
SndID_Jump =                    $A0
     rte</asm>
+
SndID_Checkpoint =              $A1
 +
SndID_SpikeSwitch =            $A2
 +
SndID_Hurt =                    $A3
 +
SndID_Skidding =                $A4
 +
SndID_BlockPush =              $A5
 +
SndID_HurtBySpikes =            $A6
 +
SndID_Sparkle =                $A7
 +
SndID_Beep =                    $A8
 +
SndID_Bwoop =                  $A9
 +
SndID_Splash =                  $AA
 +
SndID_Swish =                  $AB
 +
SndID_BossHit =                $AC
 +
SndID_InhalingBubble =          $AD
 +
SndID_ArrowFiring =            $AE
 +
SndID_LavaBall =                $AE
 +
SndID_Shield =                  $AF
 +
SndID_LaserBeam =              $B0
 +
SndID_Zap =                    $B1
 +
SndID_Drown =                  $B2
 +
SndID_FireBurn =                $B3
 +
SndID_Bumper =                  $B4
 +
SndID_Ring =                    $B5
 +
SndID_RingRight =              $B5
 +
SndID_SpikesMove =              $B6
 +
SndID_Rumbling =                $B7
 +
SndID_Smash =                  $B9
 +
SndID_DoorSlam =                $BB
 +
SndID_SpindashRelease =        $BC
 +
SndID_Hammer =                  $BD
 +
SndID_Roll =                    $BE
 +
SndID_ContinueJingle =          $BF
 +
SndID_CasinoBonus =            $C0
 +
SndID_Explosion =              $C1
 +
SndID_WaterWarning =            $C2
 +
SndID_EnterGiantRing =          $C3
 +
SndID_BossExplosion =          $C4
 +
SndID_TallyEnd =                $C5
 +
SndID_RingSpill =              $C6
 +
SndID_Flamethrower =            $C8
 +
SndID_Bonus =                  $C9
 +
SndID_SpecStageEntry =          $CA
 +
SndID_SlowSmash =              $CB
 +
SndID_Spring =                  $CC
 +
SndID_Blip =                    $CD
 +
SndID_RingLeft =                $B5
 +
SndID_Signpost =                $CF
 +
SndID_CNZBossZap =              $D0
 +
SndID_Signpost2P =              $D3
 +
SndID_OOZLidPop =              $D4
 +
SndID_SlidingSpike =            $D5
 +
SndID_CNZElevator =            $D6
 +
SndID_PlatformKnock =          $D7
 +
SndID_BonusBumper =            $D8
 +
SndID_LargeBumper =            $D9
 +
SndID_Gloop =                  $DA
 +
SndID_PreArrowFiring =          $DB
 +
SndID_Fire =                    $DC
 +
SndID_ArrowStick =              $DD
 +
SndID_Helicopter =              $DE
 +
SndID_SuperTransform =          $DF
 +
SndID_SpindashRev =            $E0
 +
SndID_Rumbling2 =              $E1
 +
SndID_CNZLaunch =              $E2
 +
SndID_Flipper =                $E3
 +
SndID_HTZLiftClick =            $E4
 +
SndID_Leaves =                  $E5
 +
SndID_MegaMackDrop =            $E6
 +
SndID_DrawbridgeMove =          $E7
 +
SndID_QuickDoorSlam =          $E8
 +
SndID_DrawbridgeDown =          $E9
 +
SndID_LaserBurst =              $EA
 +
SndID_Scatter =                $EB
 +
SndID_LaserFloor =              $EB
 +
SndID_Teleport =                $EC
 +
SndID_Error =                  $ED
 +
SndID_MechaSonicBuzz =          $EE
 +
SndID_LargeLaser =              $EF
 +
SndID_OilSlide =                $F0
 +
SndID__End     =                $F7</pre>
  
Replace it with this:
+
The following are the lines you should NOT have deleted, just for reference:
  
<asm>VintRet:
+
<pre>MusID_StopSFX = $78+$80 ; F8
    jsr    Init_Sonic1_Sound_Driver    ; init Sonic 1 sound driver
+
MusID_FadeOut = $79+$80 ; F9
    addq.l    #1,(Vint_runcount).w
+
SndID_SegaSound = $7A+$80 ; FA
    movem.l    (sp)+,d0-a6
+
MusID_SpeedUp = $7B+$80 ; FB
    rte</asm>
+
MusID_SlowDown = $7C+$80 ; FC
 +
MusID_Stop = $7D+$80 ; FD
 +
MusID_Pause = $7E+$80 ; FE
 +
MusID_Unpause = $7F+$80 ; FF</pre>
  
Next, go to JmpTo_SoundDriverLoad, and find all of this:
+
Now, find these lines:
  
<asm>JmpTo_SoundDriverLoad
+
<pre>Underwater_palette_2: ds.w palette_line_size ; not sure what it's used for but it's only used when there's water
 +
Underwater_palette_2_line2: ds.w palette_line_size
 +
Underwater_palette_2_line3: ds.w palette_line_size
 +
Underwater_palette_2_line4: ds.w palette_line_size
  
    nop
+
Underwater_palette: ds.w palette_line_size ; main palette for underwater parts of the screen
 +
Underwater_palette_line2: ds.w palette_line_size
 +
Underwater_palette_line3: ds.w palette_line_size
 +
Underwater_palette_line4: ds.w palette_line_size</pre>
  
    jmp    (SoundDriverLoad).l
+
Copy these lines to the clipboard (Or better yet, to a separate text document), we are going to be moving them in a moment.
; End of function JmpTo_SoundDriverLoad
 
  
; ===========================================================================
+
Immediately below where those lines used to be is a line like this:
  
; unused mostly-leftover subroutine to load the sound driver
+
<pre> ds.b $500 ; $FFFFF100-$FFFFF5FF ; unused, leftover from the Sonic 1 sound driver (and used by it when you port it to Sonic 2)</pre>
 +
 +
Change it to this:
  
; SoundDriverLoadS1:
+
<pre>Sound_Driver_RAM:         ds.b $600 ; $FFFFF000-$FFFFF5FF ; Used by the Sonic 2 Clone Driver.</pre>
    move.w    #$100,(Z80_Bus_Request).l ; stop the Z80
+
    move.w    #$100,(Z80_Reset).l; reset the Z80
+
The underwater palettes were overwriting some RAM that the Sonic 1/Sonic 2 Clone Driver use, so we need to move them somewhere safer. Fortunately, such a place in RAM exists.
    lea    (Z80_RAM).l,a1
 
    move.b    #$F3,(a1)+
 
    move.b    #$F3,(a1)+
 
    move.b    #$C3,(a1)+
 
    move.b    #0,(a1)+
 
    move.b    #0,(a1)+
 
    move.w    #0,(Z80_Reset).l
 
    nop
 
    nop
 
    nop
 
    nop
 
    move.w    #$100,(Z80_Reset).l ; reset the Z80
 
    move.w    #0,(Z80_Bus_Request).l ; start the Z80
 
    rts</asm>
 
  
and replace it like this:
+
What we need, are $100 free bytes. So, first off, find the line:
  
<asm>JmpTo_SoundDriverLoad
+
<pre>Normal_palette:     ds.w palette_line_size</pre>
    move.w   #$100,(Z80_Bus_Request).l ; stop the Z80
 
    move.w    #$100,(Z80_Reset).l ; reset the Z80
 
    lea    (Kos_Z80).l,a0
 
    lea    (Z80_RAM).l,a1
 
    bsr.w    KosDec
 
    move.b    #$F3,(a1)+
 
    move.b    #$F3,(a1)+
 
    move.b    #$C3,(a1)+
 
    move.b    #0,(a1)+
 
    move.b    #0,(a1)+
 
    move.w    #0,(Z80_Reset).l
 
    nop
 
    nop
 
    nop
 
    nop
 
    move.w    #$100,(Z80_Reset).l ; reset the Z80
 
    move.w    #0,(Z80_Bus_Request).l ; start the Z80
 
    rts</asm>
 
  
Next, find PlayMusic, which should look like this this:
+
Paste the underwater_palette lines  right above it.
  
<asm>; sub_135E:
+
Right above the lines you just pasted, you should see the following:
PlayMusic:
 
    tst.b    (Music_to_play).w
 
    bne.s    +
 
    move.b    d0,(Music_to_play).w
 
    rts
 
+
 
    move.b    d0,(Music_to_play_2).w
 
    rts
 
; End of function PlayMusic</asm>
 
  
And replace it with this:
+
<pre>Sprite_Table: ds.b $280 ; Sprite attribute table buffer
<asm>; sub_135E:
+
ds.b $80 ; unused, but SAT buffer can spill over into this area when there are too many sprites on-screen</pre>
PlayMusic:
+
;    tst.b   ($FFFFFFE0).w
+
Replace them both with just this:
;   bne.s    +
 
;    move.b   d0,($FFFFFFE0).w
 
    move.b    d0,($FFFFF00A).w
 
    rts
 
+
 
    move.b    d0,($FFFFF00A).w
 
    rts
 
; End of function PlayMusic</asm>
 
  
Right beneath that should be PlaySound. Replace PlaySound with this:
+
<pre>Sprite_Table: ds.b $200 ; Sprite attribute table buffer</pre>
<asm>; sub_1370
 
PlaySound:
 
    move.b   d0,($FFFFF00B).w
 
    rts
 
; End of function PlaySound</asm>
 
  
Now we need to change PlaySoundStereo, which should be right beath PlaySound.
+
==Step 4 - Introducing The New Sound Driver!==
Replace it with this:
+
Go back to s2.asm, and right above this line:
<asm>; sub_1376:
 
PlaySoundStereo:
 
    bra.s    PlayMusic    ; skip over routine (For S1 driver)
 
    move.b    d0,(SFX_to_play_2).w
 
    rts
 
; End of function PlaySoundStereo</asm>
 
  
Now PlaySoundLocal is the next thing to edit, and again, it should be right below PlaySoundStereo.
+
<pre>; end of 'ROM'</pre>
Replace it with this:
 
<asm>; sub_137C:
 
PlaySoundLocal:
 
    tst.b    render_flags(a0)
 
    bpl.s    +
 
    move.b    d0,($FFFFF00B).w
 
+
 
    rts</asm>
 
  
Below this is the routine PauseGame. Rather than replacing that entire routine, we are simply going to find this:
+
Paste this:
  
<asm>+
+
<pre> include "Sonic 2 Clone Driver.asm"</pre>
    move.w    #1,(Game_paused).w    ; freeze time
 
    move.b    #MusID_Pause,(Music_to_play).w    ; pause music</asm>
 
  
And replace it with this:
+
Now, before anything else, open up Sonic 2 Clone Driver.asm, and find and replace (CRTL+H usually) all instances of "<b>incbin</b>" with "<b>BINCLUDE</b>" (without the quotes).
  
<asm>+
+
Repeat the process, replacing all instances of "<b>@loc</b>" with "<b>.loc</b>". The Git disassembly's AS Assembler handles local labels differently, so we're converting them to compatible ones.
    move.w    #1,(Game_paused).w    ; freeze time
 
    move.b   #1,($FFFFF003).w    ; pause music</asm>
 
  
Now go to Pause_Resume, which should look like this:
+
At this point, you can build your ROM if you want. You won't get any sound, but the game will run.
  
<asm>; loc_13F2:
+
==Step 5 - Let The Music Play!==
Pause_Resume:
+
Go back to s2.asm, and find the label "<b>VintRet:</b>"
    move.b    #MusID_Unpause,(Music_to_play).w</asm>
 
  
Replace it with this:
+
In that function, right after the label, paste this line:
  
<asm>; loc_13F2:
+
<pre> jsr (Init_Sonic1_Sound_Driver).l</pre>
Pause_Resume:
 
    move.b    #$80,($FFFFF003).w</asm>
 
  
Now, find Pause_SlowMo, which should be this:
+
If you were to build your ROM again now, you still wouldn't have sound. We're going to fix that now. Go back to s2.constants.asm, and find these lines:
  
<asm>; loc_1400:
+
<pre>Music_to_play: ds.b 1
Pause_SlowMo:
+
SFX_to_play: ds.b 1 ; normal
    move.w    #1,(Game_paused).w
+
SFX_to_play_2: ds.b 1 ; alternating stereo
    move.b
+
unk_FFE3: ds.b 1
    #MusID_Unpause,(Music_to_play).w
+
Music_to_play_2: ds.b 1 ; alternate (higher priority?) slot</pre>
    rts</asm>
 
Replace it with the following:
 
  
<asm>; loc_1400:
+
Replce theme with this:
Pause_SlowMo:
 
    move.w    #1,(Game_paused).w
 
    move.b    #1,($FFFFF003).w
 
    rts</asm>
 
  
Next, find SpecialStage_Unpause, which should be this:
+
<pre> ds.b 5</pre>
  
<asm>; loc_541A:
+
Now, we need to remake the music_to_play and SFX_to_play constants, but a bit differently. Anywhere in <b>s2.constants.asm</b> you deem appropriate (for the sake of organization, let's put them after Sound_Driver_RAM:), paste this code:
SpecialStage_Unpause:
 
    move.b    #MusID_Unpause,(Music_to_play).w
 
    move.b   #8,(Vint_routine).w
 
    bra.w    WaitForVint</asm>
 
  
And replace it with this:
+
<pre>Music_Pause  = $FFFFF003
 +
Music_to_play = $FFFFF00A
 +
SFX_to_play  = $FFFFF00B</pre>
  
<asm>; loc_541A:
+
Go back to s2.asm; we've got more changes to make.
SpecialStage_Unpause:
 
    move.b    #1,($FFFFF003).w
 
    move.b    #8,(Vint_routine).w
 
    bra.w    WaitForVint</asm>
 
 
 
Finally, we're going to do something that will clean up some RAM for us later in the guide.
 
Do a search and replace (Usually CTRL+H) for "Underwater_palette_2". Replace all with "Underwater_palette".
 
I don't know why the game used two different section for underwater palettes, but I've done this change in my hack and it did no
 
  
harm.
+
First off, search and replace all instances of "<b>SFX_to_play_2</b>" with just "<b>SFX_to_play</b>", and "<b>Music_to_play_2</b>" with "<b>Music_to_play</b>".
  
We're done with the first part of this guide! Try to build your Rom, and you'll get some errors! Fun!
+
This fixes most things, but if were to play the game, both the Sega Sound and pausing the game are... REALLY messed up. Let's fix this, too.
Next up, we'll be fixing these errors.
 
  
==Step 4 - Break it until it's fixed!==
+
Find this line, again, in s2.asm
If you look at the log, you'll see a lot of errors like this one:
 
  
> > >Sonic 2 Clone Driver.asm(42): error: unknown opcode
+
<pre> move.b #MusID_Pause,(Music_to_play).w ; pause music</pre>
> > > INCBIN
+
> > > PSG7:       incbin    sound\psg7.bin
+
Replace it with this:
  
Luckily, this is a simple fix. Open up Sonic 2 Clone Driver.asm, anf find and replace (CRTL+H usually) all instances of "INCBIN" with
+
<pre> move.b #1,(Music_Pause).w ; pause music</pre>
 +
 +
And replace all instances of this line:
  
"BINCLUDE" (Without the quotes, obviously).
+
<pre>  move.b #MusID_Unpause,(Music_to_play).w</pre>
  
Now repeat the process, replacing all intances of "@loc" with "Lloc". The HG dissasembly does not like local routines, so this  
+
With this:
  
converts them into normal routines to avoid errors.
+
<pre>  move.b #$80,(Music_Pause).w ; resume music</pre>
  
Save the file, and compile the ROM again. I got 437 errors, and of course, they need to be fixed as well.
+
==Step 6 - Saaay-Gaaah!==
 +
Now, let's fix the last problem: The SEGA Sound. You can close s2.constants and s2.asm now, we're done with those.
  
On the bright side, you can close s2.asm and Sonic 2 Clone Driver.asn, they are all fixed.
+
Our target this time is Sonic 2 Clone Driver.asm.
  
==Step 5 - Strippers==
+
Search for the label '<b>SegaPCM:</b>'.
Re-Open s2.sounddriver.asm, because we need to strip it down even more.
 
  
Find zDACPtrTbl, and delete everything down to the line "idstart :=    81h"
+
Now, replace
  
Go to "zBankSwitchToMusic:", and delete the contents of that routine.(Everything between "zBankSwitchToMusic:" and "ret"
+
<pre> cnop $0, (((((*+$6978)>>$10)+$01)*$10000)-$6978)
Go to "zUpdateDAC:" and again delete everything down to "ret".
+
SegaPCM: BINCLUDE sound\segapcm.bin
 +
even</pre>
  
Now find this line:
+
    with
  
<asm>ensure1byteoffset macro maxsize</asm>
+
<pre> align $8000
 +
SegaPCM: BINCLUDE sound\segapcm.bin
 +
SegaPCM_End</pre>
  
Delete everything between that and endm, but leave those two lines, otherwise you will get errors.
+
Next, find the label '<b>PCM_Table:</b>', and immediately before:
  
If you build the ROM now, you will get 393 errors, but almost all of these are duplicates or fixed just by fixing another.
+
<pre>;--------------------------------------------------------
Don't close s2.sounddriver.asm just yet, we'll be stripping more content from that later. Right now however, we're going to fix the
+
Kos_Z80: BINCLUDE sound\z80_new.bin</pre>
  
bulk of these errors.
+
Paste this:
  
==Step 6 - Identity Crisis==
+
<pre> dc.l $A00200, SegaPCM
Open s2.constants.asm. 393 is a lot of errors, but all it takes to fix them is a copy+paste job for you.
+
dc.w (SegaPCM_End-SegaPCM)/2
 +
dc.b $09, 0</pre>
 +
 +
Finally, go to "Sound_E1:" and replace
  
Find the line "; Music IDs". You'll see this:
+
<pre> move.b #$88,($A01FFF).l</pre>
  
<asm>; Music IDs
+
with:
offset :=    zMasterPlaylist
 
ptrsize :=    1
 
idstart :=    $81
 
; $80 is reserved for silence, so if you make idstart $80 or less,
 
; you may need to insert a dummy zMusIDPtr in the $80 slot</asm>
 
  
delete everything from there down to "MusID__End =        id(zMusIDPtr__End)   ; A0", and paste the following where it used to be:
+
<pre> move.b #$88, d0
 +
jsr Calculate_PCM
 +
move.b #$81, ($A01FFF).l ; can't use #$88, because that one uses hardcoded offsets</pre>
 +
 +
And we're done! Build it, test out your fixed Sega Sound and pause screen, and have fun!
  
<asm>; Music IDs
+
==Optional step - Import Sonic 2 PSG Envelopes==
offset :=   MusicIndex
+
At this point, you shouldn't have any sound driver-related problems.
ptrsize :=   1
 
idstart :=   $81
 
; $80 is reserved for silence, so if you make idstart $80 or less,
 
; you may need to insert a dummy zMusIDPtr in the $80 slot
 
  
MusID__First =          idstart
+
However, there is one more thing you can do, and it may help certain songs (Such as EHZ's music) to sound better.
MusID_2PResult =      $81
+
In Sonic 2 Clone Driver.asm, find the label PSG_Index:. It should be early in the file, and will look like this:
MusID_EHZ =              $82
 
MusID_MCZ_2P =          $83
 
MusID_OOZ =              $84
 
MusID_MTZ =              $85
 
MusID_HTZ =              $86
 
MusID_ARZ =              $87
 
MusID_CNZ_2P =          $88
 
MusID_CNZ =              $89
 
MusID_DEZ =              $8A
 
MusID_MCZ =              $8B
 
MusID_EHZ_2P =          $8C
 
MusID_SCZ =              $8D
 
MusID_CPZ =              $8E
 
MusID_WFZ =              $8F
 
MusID_HPZ =              $90
 
MusID_Options =          $91
 
MusID_SpecStage =      $92
 
MusID_Boss =            $93
 
MusID_EndBoss =          $94
 
MusID_Ending =          $95
 
MusID_SuperSonic =    $96
 
MusID_Invincible =    $97
 
MusID_ExtraLife =      $98
 
MusID_Title =            $99
 
MusID_EndLevel =      $9A
 
MusID_GameOver =      $9B
 
MusID_Continue =      $9C
 
MusID_Emerald =          $9D
 
MusID_Credits =          $9E
 
MusID_Countdown =      $9F
 
MusID__End  =      $A0</asm>
 
 
 
The music is all fixed, now all that's left is the sound effects:
 
  
Find the line "; Sound IDs", and delete everything down to the line "; Special sound IDs". Leve the special IDs alone.
+
<pre>PSG_Index: dc.l PSG1, PSG2, PSG3
 +
dc.l PSG4, PSG5, PSG6
 +
dc.l PSG7, PSG8, PSG9
 +
PSG1: BINCLUDE sound\psg1.bin
 +
PSG2: BINCLUDE sound\psg2.bin
 +
PSG3: BINCLUDE sound\psg3.bin
 +
PSG4: BINCLUDE sound\psg4.bin
 +
PSG6: BINCLUDE sound\psg6.bin
 +
PSG5: BINCLUDE sound\psg5.bin
 +
PSG7: BINCLUDE sound\psg7.bin
 +
PSG8: BINCLUDE sound\psg8.bin
 +
PSG9: BINCLUDE sound\psg9.bin</pre>
  
In place of the text you deleted, just paste this:
+
Replace it with this:
  
<asm>; Sound IDs
+
<pre>PSG_Index: dc.l PSG1, PSG2, PSG3
offset :=    SoundIndex
+
dc.l PSG4, PSG5, PSG6
ptrsize :=    2
+
dc.l PSG7, PSG8, PSG9
idstart :=    $A0
+
dc.l PSG0A, PSG0B, PSG0C, PSG0D
 +
PSG1: BINCLUDE sound\psg1.bin
 +
PSG2: BINCLUDE sound\psg2.bin
 +
PSG3: BINCLUDE sound\psg3.bin
 +
PSG4: BINCLUDE sound\psg4.bin
 +
PSG6: BINCLUDE sound\psg6.bin
 +
PSG5: BINCLUDE sound\psg5.bin
 +
PSG7: BINCLUDE sound\psg7.bin
 +
PSG8: BINCLUDE sound\psg8.bin
 +
PSG9: BINCLUDE sound\psg9.bin
 +
PSG0A:
 +
dc.b 0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1
 +
dc.b 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
 +
dc.b 1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2
 +
dc.b 2,2,3,3,3,3,3,3,3,3,3,3,4,$80
 +
PSG0B:
 +
dc.b 4,4,4,3,3,3,2,2,2,1,1,1,1,1,1,1
 +
dc.b 2,2,2,2,2,3,3,3,3,3,4,$80
 +
PSG0C:
 +
dc.b 4,4,3,3,2,2,1,1,1,1,1,1,1,1,1,1
 +
dc.b 1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2
 +
dc.b 2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3
 +
dc.b 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
 +
dc.b 3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4
 +
dc.b 4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5
 +
dc.b 5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6
 +
dc.b 6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,$80
 +
PSG0D:
 +
dc.b $0E,$0D,$0C,$0B,$0A,9,8,7,6,5,4,3,2,1,0,$80</pre>
  
SndID__First = idstart
+
What you have done now is ported the new PSG envelopes that were added to Sonic 2. Emerald Hill Zone, and most Sonic 2 Beta songs will now sound better when ported. Note that this won't affect the music already included with the Sonic 2 Clone Driver. Thanks to ValleyBell for this addition.
SndID_Jump =                    $A0                ; A0
 
SndID_Checkpoint =            $A1              ; A1
 
SndID_SpikeSwitch =            $A2              ; A2
 
SndID_Hurt =                    $A3                ; A3
 
SndID_Skidding =              $A4                ; A4
 
SndID_BlockPush =              $A5              ; A5
 
SndID_HurtBySpikes =          $A6      ; A6
 
SndID_Sparkle =                $A7
 
SndID_Beep =                  $A8
 
SndID_Bwoop =                  $A9
 
SndID_Splash =                $AA
 
SndID_Swish =                  $AB
 
SndID_BossHit =                $AC
 
SndID_InhalingBubble =        $AD
 
SndID_ArrowFiring =            $AE
 
SndID_LavaBall =              $AE
 
SndID_Shield =                $Af
 
SndID_LaserBeam =              $B0
 
SndID_Zap =                    $B1
 
SndID_Drown =                  $B2
 
SndID_FireBurn =              $B3
 
SndID_Bumper =                $B4
 
SndID_Ring =                  $B5    ; B5
 
SndID_RingRight =              $B5
 
SndID_SpikesMove =            $B6
 
SndID_Rumbling =              $B7
 
SndID_Smash =                  $B9
 
SndID_DoorSlam =              $BB
 
SndID_SpindashRelease =        $BC    ; BC
 
SndID_Hammer =                $BD
 
SndID_Roll =                  $BE
 
SndID_ContinueJingle =        $BF
 
SndID_CasinoBonus =            $C0
 
SndID_Explosion =              $C1
 
SndID_WaterWarning =          $C2
 
SndID_EnterGiantRing =        $C3
 
SndID_BossExplosion =          $C4
 
SndID_TallyEnd =              $C5
 
SndID_RingSpill =              $C6
 
SndID_Flamethrower =          $C8
 
SndID_Bonus =                  $C9
 
SndID_SpecStageEntry =        $CA
 
SndID_SlowSmash =              $CB
 
SndID_Spring =                $CC
 
SndID_Blip =                  $CD
 
SndID_RingLeft =              $B5
 
SndID_Signpost =              $CF
 
SndID_CNZBossZap =            $D0
 
SndID_Signpost2P =            $D3
 
SndID_OOZLidPop =                $D4
 
SndID_SlidingSpike =          $D5
 
SndID_CNZElevator =            $D6
 
SndID_PlatformKnock =          $D7
 
SndID_BonusBumper =            $D8
 
SndID_LargeBumper =            $D9
 
SndID_Gloop =                  $DA
 
SndID_PreArrowFiring =        $DB
 
SndID_Fire =                  $DC
 
SndID_ArrowStick =            $DD
 
SndID_Helicopter =            $DE
 
SndID_SuperTransform =        $DF
 
SndID_SpindashRev =            $E0
 
SndID_Rumbling2 =              $E1
 
SndID_CNZLaunch =              $E2
 
SndID_Flipper =                $E3
 
SndID_HTZLiftClick =          $E4
 
SndID_Leaves =                $E5
 
SndID_MegaMackDrop =          $E6
 
SndID_DrawbridgeMove =        $E7
 
SndID_QuickDoorSlam =          $E8
 
SndID_DrawbridgeDown =        $E9
 
SndID_LaserBurst =            $EA
 
SndID_Scatter =                $EB
 
SndID_LaserFloor =            $EB
 
SndID_Teleport =              $EC
 
SndID_Error =                  $ED
 
SndID_MechaSonicBuzz =        $EE
 
SndID_LargeLaser =            $EF
 
SndID_OilSlide =              $F0
 
SndID__End    =            $F7</asm>
 
  
==Step 7 - I am Error==
+
==Reccomended Extra Step: Equating The RAM==
Now we are going back to s2.sounddriver.asm.
 
There are 4 more errors here.
 
As before, we're going to solve this by simply emptying out the relavent routines. We can't just delete stuff because a few things in it
 
  
are still going to be referenced.
+
If you're like me, then you've shifted at least some RAM values in your hack around. Because of this, you might notice you've have some problems with the sound driver... Nothing there is equated, so it uses fixed RAM addresses!
So the first Routine to clean out is zDACAfterDur. change that and  remove zloc_22A inside it so it looks like this:
+
This won't do at all, so let's make a constant so you can shift the data around all you like.
  
<asm>zDACAfterDur:
+
To start, open <b>s2.constants.asm</b>, and find Music_Pause, Music_to_play, and SFX_to_play.
    ret</asm>
+
Change them to this:
 
 
There is one more routine to empty. That routine is zloc_78E, or zBGMLoad. Starting at this line:
 
  
<asm>zBGMLoad:</asm>
+
<pre>Music_Pause  = Sound_Driver_RAM+3
 +
Music_to_play = Sound_Driver_RAM+$A
 +
SFX_to_play  = Sound_Driver_RAM+$B</pre>
  
delete everything down to here:
+
<b>Note:</b> If you followed this guide before January 5th, 2014, you may need to change the $600 bytes you reserved for the Sound Driver in your <b>s2.constants.asm</b> to this:
  
<asm>   ; End of DAC/FM init, begin PSG init</asm>
+
<pre>Sound_Driver_RAM: ds.b $600</pre>
 
+
This label is important, and it's a new addition. If you are following this guide after January 5th, I had you put the label in by default.
And there you have it! Close s2.sounddriver.asm, Build you ROM and test it!
 
  
==Additional Step==
+
Now you're done here, that's all we're going to use s2.constants.asm for. Open <b>Sonic 2 Clone Driver.asm</b> for the rest of the process.
Uh-oh! if you've played up to Chemical Plant Zone Act 2, you'll notice the driver crashes on that level!
 
  
This is because of water. In Sonic 2, the underwater palettes are stored in a section of RAM that is now used by the sound driver,
+
In <b>Sonic 2 Clone Driver.asm</b>, go to the label <b>loc_71B82:</b>, and change this line:
 +
<pre> lea ($FFF000).l,a6</pre>
 +
To this:
 +
<pre> lea (Sound_Driver_RAM).l,a6</pre>
 +
a6 is the base address of the sound driver. This will fix 90% of your potential issues.
  
because it's based on Sonic 1's sound driver.
+
Fixing the rest is where dword_722CC and dword_722EC come into play.  
What we need to do now is relocate the water palette table in RAM, so the Sound Driver can do what it likes. I am going to assume
 
  
you haven't modified the RAM allocation in your hack here, and go step by step. If you have modifying the RAM in your game, you
+
Replace both tables with these:
  
are probably on your own.
+
<pre>dword_722CC:
 +
dc.l Sound_Driver_RAM+$0D0 ; FM3
 +
dc.l 0 ; dummy
 +
dc.l Sound_Driver_RAM+$100 ; FM4
 +
dc.l Sound_Driver_RAM+$130 ; FM5
 +
dc.l Sound_Driver_RAM+$190 ; PSG1
 +
dc.l Sound_Driver_RAM+$1C0 ; PSG2
 +
dc.l Sound_Driver_RAM+$1F0 ; Plain PSG3
 +
dc.l Sound_Driver_RAM+$1F0 ; Noise
 +
dword_722EC:
 +
dc.l Sound_Driver_RAM+$220 ; SFX FM3
 +
dc.l 0 ; dummy
 +
dc.l Sound_Driver_RAM+$250 ; SFX FM4
 +
dc.l Sound_Driver_RAM+$280 ; SFX FM5
 +
dc.l Sound_Driver_RAM+$2B0 ; SFX PSG1
 +
dc.l Sound_Driver_RAM+$2E0 ; SFX PSG2
 +
dc.l Sound_Driver_RAM+$310 ; Plain PSG3
 +
dc.l Sound_Driver_RAM+$310 ; Noise</pre>
  
Let's go back to s2.constants.asm, and find these lines:
+
Also, their proper names would be BGMChannelRAM and SFXChannelRAM, respectively. You can rename them if you want, but it's not necessary.
 
 
<asm>Underwater_palette_2:        ds.w palette_line_size    ; not sure what it's used for but it's only used when there's water
 
Underwater_palette_2_line2:    ds.w palette_line_size
 
Underwater_palette_2_line3:    ds.w palette_line_size
 
Underwater_palette_2_line4:    ds.w palette_line_size
 
 
 
Underwater_palette:        ds.w palette_line_size    ; main palette for underwater parts of the screen
 
Underwater_palette_line2:    ds.w palette_line_size
 
Underwater_palette_line3:    ds.w palette_line_size
 
Underwater_palette_line4:    ds.w palette_line_size
 
 
 
                ds.b    $500    ; $FFFFF100-$FFFFF5FF ; unused, leftover from the Sonic 1 sound driver (and used by it when you port it to
 
 
 
Sonic 2)
 
</asm>
 
The last four lines before the ds.b $500 are used by the sound driver now, in addition to the 500 that is labeled as such.
 
 
 
Replace all of the above lines with this:
 
 
 
<asm>              ds.b  $100  ; Sonic 1 Sound Driver
 
                    ds.b    $500    ; Sonic 1 Sound Driver</asm>
 
 
 
After doing that, you will need to find at least $80 free bytes in RAM (besides the space we just put in)
 
Fortunately, there is an area of RAM that has $C0 free bytes, and that is where the four lines we lost will go. Search for this:
 
 
 
<asm>CNZ_saucer_data:</asm>
 
 
 
And you will see this:
 
 
 
<asm>CNZ_saucer_data:        ds.b    $40    ; the number of saucer bumpers in a group which have been destroyed. Used to decide when to give 500 points instead of 10
 
                ds.b    $C0    ; $FFFFE740-$FFFFE7FF ; unused as far as I can tell
 
Ring_Positions:            ds.b    $600</asm>
 
 
 
Replace it with this:
 
  
<asm>CNZ_saucer_data:       ds.b   $40    ; the number of saucer bumpers in a group which have been destroyed. Used to decide when to give 500 points instead of 10
+
Finally, go to <b>loc_71C88:</b>. There are two lines to make note of:
Underwater_palette:        ds.w palette_line_size    ; main palette for underwater parts of the screen
+
<pre> cmp.b  #0,($FFFFFF3A).w
Underwater_palette_line2:    ds.w palette_line_size
+
bgt.s locret_71CAA</pre>
Underwater_palette_line3:    ds.w palette_line_size
+
These lines can be commented out, as they don't do much besides muting the DAC chnnel when set, and aren't ever used normally.
Underwater_palette_line4:    ds.w palette_line_size
+
If desired, you can also set them to any old unused RAM value.
                ds.b    $40    ; $FFFFE740-$FFFFE7FF ; unused as far as I can tell
 
Ring_Positions:            ds.b    $600</asm>
 
  
Build it, and test!
+
Once you've done that, you should be able to shift RAM around all you want without the sound driver screwing up!
  
The sega sound will be glitched up, and you can fix it by following this link. Everything that needs to be fixed will be in "Sonic 2 Clone Driver.asm".
 
 
==Credits==
 
==Credits==
 
     Varion Icaria - Puto's sound driver port.
 
     Varion Icaria - Puto's sound driver port.
Line 576: Line 475:
 
     Puto - Fixes for underwater palette stuff, as well as special stage ring stuff, and various other fixes to the original guide.
 
     Puto - Fixes for underwater palette stuff, as well as special stage ring stuff, and various other fixes to the original guide.
 
     Tweaker - Wrote the orignal guide to port Sonic 1's sound driver into Sonic 2.
 
     Tweaker - Wrote the orignal guide to port Sonic 1's sound driver into Sonic 2.
     ValleyBell - lots of miscallanious help to get this to work, as well as worked on the Sonic 2 Clone Driver.
+
    ShadowsofYesterday - Telling me the fix for the SEGA sound. (old version of the guide)
    ShadowsofYesterday - Telling me the fix for the SEGA sound.
+
     ValleyBell - In addition to his original work on the Sonic 2 Clone Driver, he showed me numerous things I could do to fix the guide. He also helped me with the equating process. Thanks, ValleyBell!
     Caverns4 - I wrote this guide!
+
     Caverns 4 - I wrote and updated the guide.
  
 
{{S2Howtos}}
 
{{S2Howtos}}
  
[[Category:SCHG How-tos|{{PAGENAME}}]]
+
|{{PAGENAME}}]]

Latest revision as of 10:52, 25 August 2018

(Original guide by Caverns 4)

WARNING

DO NOT USE THIS GUIDE. This is only here for archival purposes, and is using a shoddy old version of the driver. Get
Sonic Retro
Clownacy's new version of the Clone Driver
and use that for your hacks instead.
~ Caverns 4 18:26, 8 July 2014 (UTC)

If you want proof of how shoddy the old Sonic 2 Clone Driver is, look at the list of negatives a few paragraphs down. They're all fixed the Sonic 2 Clone Driver v2. ~ Clownacy

Summary

The guide is fixed and updated as of September 11th, 2013. It should now work on real hardware! ~ Caverns 4

The Sonic 2 Clone Driver is simply a modified version of Sonic 1's sound driver, designed to work with Sonic 2. The advantages to using this over Sonic 2's sound driver normally are numerous; It will be easier to modify existing songs as you won't have to worry about compressing and decompressing the music, and your music will be supported by more up to date Music editor programs.

There are many inaccuracies with the Sonic 2 Clone Driver, however. One is that the Spin Dash's rev sound will not raise pitch. The music is also not a perfect adaptation of Sonic 2's music, particularly sometimes the PSG channels sound slightly different (unless you do the optional step that adds Sonic 2 PSGs, at least.) This is most noticeable in Emerald Hill Zone's music. The tempos of some songs are also slightly different, along with the Speed Shoes tempos being outright wrong, some even slowing down the music. CPZ's Gloop sound will also play twice as often as it should. Sound priorities are also incorrect, leading to some sounds being able to interrupt others when they shouldn't. As is the case in Sonic 1, on PAL consoles, the music will play at a slowed speed.

If the above bugs will not bother you too badly, then you'll like using the Sonic 2 Clone Driver after working with Sonic 2's own sound driver. The Sonic 2 Clone Driver is much easier to port music to, and in fact, Sonic 1 music can even just be binclude'd into the ROM. This is because it's based on Sonic 1's sound driver, and uses the same formatting. With this out of the way, now it's time to edit the Sonic 2 Git Disassembly!

Before beginning, you will need the following file:

Download.svg Download Sonic 2 Clone Driver Files
File: Sonic 2 Clone Driver.7z (78 kB) (info)

Step 1 - Getting Started

Back up your disassembly if you haven't already.

To start, go into your sound folder, where you'll have a DAC folder, a music folder, and a PCM folder.

DELETE THEM ALL!

Also delete s2.sounddriver.asm. These are all parts of Sonic 2's sound driver, so they won't be necessary.

Then extract "Sonic 2 Clone Driver.7z" into the main folder of your disassembly.

Step 2 - Deleting Leftovers

Now open up s2.asm, and find the label 'SoundDriverLoad:'. Delete everything from that, up to and including:

Mus_Continue:   BINCLUDE    "sound/music/Continue.bin"

What we have done here is deleted the routines to load and decompress Sonic 2's sound driver. We don't need this anymore.

Next up, find this line:

	cnop -Size_of_SEGA_sound, $8000

and delete everything from there up to (but not including) the line:

; end of 'ROM'

Also, on the line above the 'EndOfRom:' label, you should see this:

	shared word_728C_user,Obj5F_MapUnc_7240,off_3A294,MapRUnc_Sonic,movewZ80CompSize

Change it to this:

	shared word_728C_user,Obj5F_MapUnc_7240,off_3A294,MapRUnc_Sonic

Finally, find the label 'sndDriverInput:'

Delete the entire function, which starts there, and ends at this line:

; End of function sndDriverInput

Now search in your assembly for "sndDriverInput", and delete any lines that point to it. There will be quite a few, but it won't hurt anything.

We've effectively deleted the old sound driver entirely from our game... Now it's time we implemented our new one... But first, we need to prepare s2.constants.asm!

Step 3 - Overhauling Constants, Fixing RAM

Open s2.constants.asm, and find the following line:

Find the line "; Music IDs". You'll see this:

; Music IDs
offset :=    zMasterPlaylist
ptrsize :=    1
idstart :=    $81
; $80 is reserved for silence, so if you make idstart $80 or less,
; you may need to insert a dummy zMusIDPtr in the $80 slot

Delete everything from there down to "MusID__End = id(zMusIDPtr__End)  ; A0", and paste the following where it used to be:

; Music IDs
; $80 is reserved for silence, so if you make idstart $80 or less,
; you may need to insert a dummy zMusIDPtr in the $80 slot
MusID__First =          $81
MusID_2PResult =        $81
MusID_EHZ =             $82
MusID_MCZ_2P =          $83
MusID_OOZ =             $84
MusID_MTZ =             $85
MusID_HTZ =             $86
MusID_ARZ =             $87
MusID_CNZ_2P =          $88
MusID_CNZ =             $89
MusID_DEZ =             $8A
MusID_MCZ =             $8B
MusID_EHZ_2P =          $8C
MusID_SCZ =             $8D
MusID_CPZ =             $8E
MusID_WFZ =             $8F
MusID_HPZ =             $90
MusID_Options =         $91
MusID_SpecStage =       $92
MusID_Boss =            $93
MusID_EndBoss =         $94
MusID_Ending =          $95
MusID_SuperSonic =      $96
MusID_Invincible =      $97
MusID_ExtraLife =       $98
MusID_Title =           $99
MusID_EndLevel =        $9A
MusID_GameOver =        $9B
MusID_Continue =        $9C
MusID_Emerald =         $9D
MusID_Credits =         $9E
MusID_Countdown =       $9F
MusID__End   =          $A0

The music is all fixed, now all that's left is the sound effects:

Find the line "; Sound IDs", and delete everything down to the line "; Special sound IDs". Leave the special IDs alone.

In place of the text you deleted, just paste this:

; Sound IDs
SndID__First =                  $A0
SndID_Jump =                    $A0
SndID_Checkpoint =              $A1
SndID_SpikeSwitch =             $A2
SndID_Hurt =                    $A3
SndID_Skidding =                $A4
SndID_BlockPush =               $A5
SndID_HurtBySpikes =            $A6
SndID_Sparkle =                 $A7
SndID_Beep =                    $A8
SndID_Bwoop =                   $A9
SndID_Splash =                  $AA
SndID_Swish =                   $AB
SndID_BossHit =                 $AC
SndID_InhalingBubble =          $AD
SndID_ArrowFiring =             $AE
SndID_LavaBall =                $AE
SndID_Shield =                  $AF
SndID_LaserBeam =               $B0
SndID_Zap =                     $B1
SndID_Drown =                   $B2
SndID_FireBurn =                $B3
SndID_Bumper =                  $B4
SndID_Ring =                    $B5
SndID_RingRight =               $B5
SndID_SpikesMove =              $B6
SndID_Rumbling =                $B7
SndID_Smash =                   $B9
SndID_DoorSlam =                $BB
SndID_SpindashRelease =         $BC
SndID_Hammer =                  $BD
SndID_Roll =                    $BE
SndID_ContinueJingle =          $BF
SndID_CasinoBonus =             $C0
SndID_Explosion =               $C1
SndID_WaterWarning =            $C2
SndID_EnterGiantRing =          $C3
SndID_BossExplosion =           $C4
SndID_TallyEnd =                $C5
SndID_RingSpill =               $C6
SndID_Flamethrower =            $C8
SndID_Bonus =                   $C9
SndID_SpecStageEntry =          $CA
SndID_SlowSmash =               $CB
SndID_Spring =                  $CC
SndID_Blip =                    $CD
SndID_RingLeft =                $B5
SndID_Signpost =                $CF
SndID_CNZBossZap =              $D0
SndID_Signpost2P =              $D3
SndID_OOZLidPop =               $D4
SndID_SlidingSpike =            $D5
SndID_CNZElevator =             $D6
SndID_PlatformKnock =           $D7
SndID_BonusBumper =             $D8
SndID_LargeBumper =             $D9
SndID_Gloop =                   $DA
SndID_PreArrowFiring =          $DB
SndID_Fire =                    $DC
SndID_ArrowStick =              $DD
SndID_Helicopter =              $DE
SndID_SuperTransform =          $DF
SndID_SpindashRev =             $E0
SndID_Rumbling2 =               $E1
SndID_CNZLaunch =               $E2
SndID_Flipper =                 $E3
SndID_HTZLiftClick =            $E4
SndID_Leaves =                  $E5
SndID_MegaMackDrop =            $E6
SndID_DrawbridgeMove =          $E7
SndID_QuickDoorSlam =           $E8
SndID_DrawbridgeDown =          $E9
SndID_LaserBurst =              $EA
SndID_Scatter =                 $EB
SndID_LaserFloor =              $EB
SndID_Teleport =                $EC
SndID_Error =                   $ED
SndID_MechaSonicBuzz =          $EE
SndID_LargeLaser =              $EF
SndID_OilSlide =                $F0
SndID__End     =                $F7

The following are the lines you should NOT have deleted, just for reference:

MusID_StopSFX =		$78+$80			; F8
MusID_FadeOut =		$79+$80			; F9
SndID_SegaSound =	$7A+$80			; FA
MusID_SpeedUp =		$7B+$80			; FB
MusID_SlowDown =	$7C+$80			; FC
MusID_Stop =		$7D+$80			; FD
MusID_Pause =		$7E+$80			; FE
MusID_Unpause =		$7F+$80			; FF

Now, find these lines:

Underwater_palette_2:		ds.w palette_line_size	; not sure what it's used for but it's only used when there's water
Underwater_palette_2_line2:	ds.w palette_line_size
Underwater_palette_2_line3:	ds.w palette_line_size
Underwater_palette_2_line4:	ds.w palette_line_size

Underwater_palette:		ds.w palette_line_size	; main palette for underwater parts of the screen
Underwater_palette_line2:	ds.w palette_line_size
Underwater_palette_line3:	ds.w palette_line_size
Underwater_palette_line4:	ds.w palette_line_size

Copy these lines to the clipboard (Or better yet, to a separate text document), we are going to be moving them in a moment.

Immediately below where those lines used to be is a line like this:

				ds.b	$500	; $FFFFF100-$FFFFF5FF ; unused, leftover from the Sonic 1 sound driver (and used by it when you port it to Sonic 2)

Change it to this:

Sound_Driver_RAM:          ds.b	$600	; $FFFFF000-$FFFFF5FF ; Used by the Sonic 2 Clone Driver.

The underwater palettes were overwriting some RAM that the Sonic 1/Sonic 2 Clone Driver use, so we need to move them somewhere safer. Fortunately, such a place in RAM exists.

What we need, are $100 free bytes. So, first off, find the line:

Normal_palette:			    ds.w	palette_line_size

Paste the underwater_palette lines right above it.

Right above the lines you just pasted, you should see the following:

Sprite_Table:			ds.b	$280	; Sprite attribute table buffer
				ds.b	$80	; unused, but SAT buffer can spill over into this area when there are too many sprites on-screen

Replace them both with just this:

Sprite_Table:			ds.b	$200	; Sprite attribute table buffer

Step 4 - Introducing The New Sound Driver!

Go back to s2.asm, and right above this line:

; end of 'ROM'

Paste this:

	include "Sonic 2 Clone Driver.asm"

Now, before anything else, open up Sonic 2 Clone Driver.asm, and find and replace (CRTL+H usually) all instances of "incbin" with "BINCLUDE" (without the quotes).

Repeat the process, replacing all instances of "@loc" with ".loc". The Git disassembly's AS Assembler handles local labels differently, so we're converting them to compatible ones.

At this point, you can build your ROM if you want. You won't get any sound, but the game will run.

Step 5 - Let The Music Play!

Go back to s2.asm, and find the label "VintRet:"

In that function, right after the label, paste this line:

	jsr	(Init_Sonic1_Sound_Driver).l

If you were to build your ROM again now, you still wouldn't have sound. We're going to fix that now. Go back to s2.constants.asm, and find these lines:

Music_to_play:			ds.b	1
SFX_to_play:			ds.b	1	; normal
SFX_to_play_2:			ds.b	1	; alternating stereo
unk_FFE3:			ds.b	1
Music_to_play_2:		ds.b	1	; alternate (higher priority?) slot

Replce theme with this:

			ds.b	5

Now, we need to remake the music_to_play and SFX_to_play constants, but a bit differently. Anywhere in s2.constants.asm you deem appropriate (for the sake of organization, let's put them after Sound_Driver_RAM:), paste this code:

Music_Pause   = $FFFFF003
Music_to_play = $FFFFF00A
SFX_to_play   = $FFFFF00B

Go back to s2.asm; we've got more changes to make.

First off, search and replace all instances of "SFX_to_play_2" with just "SFX_to_play", and "Music_to_play_2" with "Music_to_play".

This fixes most things, but if were to play the game, both the Sega Sound and pausing the game are... REALLY messed up. Let's fix this, too.

Find this line, again, in s2.asm

 move.b	#MusID_Pause,(Music_to_play).w	; pause music

Replace it with this:

 move.b	#1,(Music_Pause).w	; pause music

And replace all instances of this line:

  move.b	#MusID_Unpause,(Music_to_play).w

With this:

  move.b	#$80,(Music_Pause).w	; resume music

Step 6 - Saaay-Gaaah!

Now, let's fix the last problem: The SEGA Sound. You can close s2.constants and s2.asm now, we're done with those.

Our target this time is Sonic 2 Clone Driver.asm.

Search for the label 'SegaPCM:'.

Now, replace
		cnop $0, (((((*+$6978)>>$10)+$01)*$10000)-$6978)
SegaPCM:	BINCLUDE	sound\segapcm.bin
		even
   with
			align $8000
SegaPCM:	BINCLUDE	sound\segapcm.bin
SegaPCM_End

Next, find the label 'PCM_Table:', and immediately before:

;--------------------------------------------------------
Kos_Z80: BINCLUDE	sound\z80_new.bin

Paste this:

		dc.l	$A00200, SegaPCM
		dc.w	(SegaPCM_End-SegaPCM)/2
		dc.b	$09, 0

Finally, go to "Sound_E1:" and replace

		move.b	#$88,($A01FFF).l

with:

		move.b	#$88, d0
		jsr	Calculate_PCM
		move.b	#$81, ($A01FFF).l	; can't use #$88, because that one uses hardcoded offsets

And we're done! Build it, test out your fixed Sega Sound and pause screen, and have fun!

Optional step - Import Sonic 2 PSG Envelopes

At this point, you shouldn't have any sound driver-related problems.

However, there is one more thing you can do, and it may help certain songs (Such as EHZ's music) to sound better. In Sonic 2 Clone Driver.asm, find the label PSG_Index:. It should be early in the file, and will look like this:

PSG_Index:	dc.l PSG1, PSG2, PSG3
		dc.l PSG4, PSG5, PSG6
		dc.l PSG7, PSG8, PSG9
PSG1:		BINCLUDE	sound\psg1.bin
PSG2:		BINCLUDE	sound\psg2.bin
PSG3:		BINCLUDE	sound\psg3.bin
PSG4:		BINCLUDE	sound\psg4.bin
PSG6:		BINCLUDE	sound\psg6.bin
PSG5:		BINCLUDE	sound\psg5.bin
PSG7:		BINCLUDE	sound\psg7.bin
PSG8:		BINCLUDE	sound\psg8.bin
PSG9:		BINCLUDE	sound\psg9.bin

Replace it with this:

PSG_Index:	dc.l PSG1, PSG2, PSG3
		dc.l PSG4, PSG5, PSG6
		dc.l PSG7, PSG8, PSG9
		dc.l PSG0A, PSG0B, PSG0C, PSG0D
PSG1:		BINCLUDE	sound\psg1.bin
PSG2:		BINCLUDE	sound\psg2.bin
PSG3:		BINCLUDE	sound\psg3.bin
PSG4:		BINCLUDE	sound\psg4.bin
PSG6:		BINCLUDE	sound\psg6.bin
PSG5:		BINCLUDE	sound\psg5.bin
PSG7:		BINCLUDE	sound\psg7.bin
PSG8:		BINCLUDE	sound\psg8.bin
PSG9:		BINCLUDE	sound\psg9.bin
PSG0A:
	dc.b	0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1
	dc.b	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
	dc.b	1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2
	dc.b	2,2,3,3,3,3,3,3,3,3,3,3,4,$80
PSG0B:
	dc.b	4,4,4,3,3,3,2,2,2,1,1,1,1,1,1,1
	dc.b	2,2,2,2,2,3,3,3,3,3,4,$80
PSG0C:
	dc.b	4,4,3,3,2,2,1,1,1,1,1,1,1,1,1,1
	dc.b	1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2
	dc.b	2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3
	dc.b	3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
	dc.b	3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4
	dc.b	4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5
	dc.b	5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6
	dc.b	6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,$80
PSG0D:
	dc.b	$0E,$0D,$0C,$0B,$0A,9,8,7,6,5,4,3,2,1,0,$80

What you have done now is ported the new PSG envelopes that were added to Sonic 2. Emerald Hill Zone, and most Sonic 2 Beta songs will now sound better when ported. Note that this won't affect the music already included with the Sonic 2 Clone Driver. Thanks to ValleyBell for this addition.

Reccomended Extra Step: Equating The RAM

If you're like me, then you've shifted at least some RAM values in your hack around. Because of this, you might notice you've have some problems with the sound driver... Nothing there is equated, so it uses fixed RAM addresses! This won't do at all, so let's make a constant so you can shift the data around all you like.

To start, open s2.constants.asm, and find Music_Pause, Music_to_play, and SFX_to_play. Change them to this:

Music_Pause   = Sound_Driver_RAM+3
Music_to_play = Sound_Driver_RAM+$A
SFX_to_play   = Sound_Driver_RAM+$B

Note: If you followed this guide before January 5th, 2014, you may need to change the $600 bytes you reserved for the Sound Driver in your s2.constants.asm to this:

Sound_Driver_RAM: ds.b	$600

This label is important, and it's a new addition. If you are following this guide after January 5th, I had you put the label in by default.

Now you're done here, that's all we're going to use s2.constants.asm for. Open Sonic 2 Clone Driver.asm for the rest of the process.

In Sonic 2 Clone Driver.asm, go to the label loc_71B82:, and change this line:

		lea	($FFF000).l,a6

To this:

		lea	(Sound_Driver_RAM).l,a6

a6 is the base address of the sound driver. This will fix 90% of your potential issues.

Fixing the rest is where dword_722CC and dword_722EC come into play.

Replace both tables with these:

dword_722CC:
	dc.l Sound_Driver_RAM+$0D0	; FM3
	dc.l 0		; dummy
	dc.l Sound_Driver_RAM+$100	; FM4
	dc.l Sound_Driver_RAM+$130	; FM5
	dc.l Sound_Driver_RAM+$190	; PSG1
	dc.l Sound_Driver_RAM+$1C0	; PSG2
	dc.l Sound_Driver_RAM+$1F0	; Plain PSG3
	dc.l Sound_Driver_RAM+$1F0	; Noise
dword_722EC:
	dc.l Sound_Driver_RAM+$220	; SFX FM3
	dc.l 0		; dummy
	dc.l Sound_Driver_RAM+$250	; SFX FM4
	dc.l Sound_Driver_RAM+$280	; SFX FM5
	dc.l Sound_Driver_RAM+$2B0	; SFX PSG1
	dc.l Sound_Driver_RAM+$2E0	; SFX PSG2
	dc.l Sound_Driver_RAM+$310	; Plain PSG3
	dc.l Sound_Driver_RAM+$310	; Noise

Also, their proper names would be BGMChannelRAM and SFXChannelRAM, respectively. You can rename them if you want, but it's not necessary.

Finally, go to loc_71C88:. There are two lines to make note of:

		cmp.b   #0,($FFFFFF3A).w
		bgt.s	locret_71CAA

These lines can be commented out, as they don't do much besides muting the DAC chnnel when set, and aren't ever used normally. If desired, you can also set them to any old unused RAM value.

Once you've done that, you should be able to shift RAM around all you want without the sound driver screwing up!

Credits

   Varion Icaria - Puto's sound driver port.
   Esrael - Tweakers driver port, plus fixes for things broken in Puto's port, such as hanging on the title card. Extra thanks for fixing the Sega sound.
   Puto - Fixes for underwater palette stuff, as well as special stage ring stuff, and various other fixes to the original guide.
   Tweaker - Wrote the orignal guide to port Sonic 1's sound driver into Sonic 2.
   ShadowsofYesterday - Telling me the fix for the SEGA sound. (old version of the guide)
   ValleyBell - In addition to his original work on the Sonic 2 Clone Driver, he showed me numerous things I could do to fix the guide. He also helped me with the equating process. Thanks, ValleyBell!
   Caverns 4 - I wrote and updated the guide.
SCHG How-To Guide: Sonic the Hedgehog 2 (16-bit)
Fixing Bugs
Fix Demo Playback | Fix a Race Condition with Pattern Load Cues | Fix Super Sonic Bugs | Use Correct Height When Roll Jumping | Fix Jump Height Bug When Exiting Water | Fix Screen Boundary Spin Dash Bug | Correct Drowning Bugs | Fix Camera Y Position for Tails | Fix Tails Subanimation Error | Fix Tails' Respawn Speeds | Fix Accidental Deletion of Scattered Rings | Fix Ring Timers | Fix Rexon Crash | Fix Monitor Collision Bug | Fix EHZ Deformation Bug | Correct CPZ Boss Attack Behavior | Fix Bug in ARZ Boss Arrow's Platform Behavior | Fix ARZ Boss Walking on Air Glitch | Fix ARZ Boss Sprite Behavior | Fix Multiple CNZ Boss Bugs | Fix HTZ Background Scrolling Mountains | Fix OOZ Launcher Speed Up Glitch | Fix DEZ Giant Mech Collision Glitch | Fix Boss Deconstruction Behavior | Fix Speed Bugs | Fix 14 Continues Cheat | Fix Debug Mode Crash | Fix 99+ Lives | Fix Sonic 2's Sega Screen
Design Choices
Remove the Air Speed Cap | Disable Floor Collision While Dying | Modify Super Sonic Transformation Methods & Behavior | Enable/Disable Tails in Certain Levels | Collide with Water After Being Hurt | Retain Rings When Returning at a Star Post | Improve the Fade In\Fade Out Progression Routines | Fix Scattered Rings' Underwater Physics | Insert LZ Water Ripple Effect | Restore Lost CPZ Boss Feature | Prevent SCZ Tornado Spin Dash Death | Improve ObjectMove Subroutines | Port S3K Rings Manager | Port S3K Object Manager | Port S3K Priority Manager | Edit Level Order with ASM‎ | Alter Ring Requirements in Special Stages | Make Special Stage Characters Use Normal DPLCs | Speed Up Ring Loss Process | Change spike behaviour in Sonic 2
Adding Features
Create Insta-kill and High Jump Monitors | Create Clone and Special Stage Monitors | Port Knuckles
Sound Features
Expand Music Index to Start at $00 | Port Sonic 1 Sound Driver | Port Sonic 2 Clone Driver | Port Sonic 3 Sound Driver | Port Flamewing's Sonic 3 & Knuckles Sound Driver | Expand the Music Index to Start at $00 (Sonic 2 Clone Driver Version) | Play Different Songs Per Act
Extending the Game
Extend the Level Index Past $10 | Extend the Level Select | Extend Water Tables | Add Extra Characters | Free Up 2 Universal SSTs


|Port the Sonic 2 Clone Sound Driver to the HG version of Sonic 2]]