(Original guide by Caverns 4)
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
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 Sonic 2 Clone Driver Files
File: Sonic 2 Clone Driver.7z (78 kB) (info)
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.
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:
Change it to this:
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!
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
Go back to s2.asm, and right above this line:
; end of 'ROM'
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.
Go back to s2.asm, and find the label "VintRet:"
In that function, right after the label, paste this line:
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:
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 #$80,(Music_Pause).w ; resume music
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:'.
cnop $0, (((((*+$6978)>>$10)+$01)*$10000)-$6978) SegaPCM: BINCLUDE sound\segapcm.bin even
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
dc.l $A00200, SegaPCM dc.w (SegaPCM_End-SegaPCM)/2 dc.b $09, 0
Finally, go to "Sound_E1:" and replace
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!
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.
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:
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!
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)|
|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 Spin Dash Code and Add Spin Dash Speeds | 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|
|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|
|Create Insta-kill and High Jump Monitors | Create Clone and Special Stage Monitors | Port Knuckles|
|Port Sonic 1 Sound Driver | Port Sonic 2 Clone Driver | Port Sonic 3 Sound Driver | Expand the Music Index to Start at $00 (Sonic 2 Clone Driver Version)|
|Extending the Game|
|Extend the Level Index Past $10 | Extend the Level Select | Extend Water Tables | Add Extra Characters | Free Up 2 Universal SSTs|